본문 바로가기
Develop Study/Spring 2025. 5. 8.

(25.05.08) Spring Boot 설정값 주입 : @ConfigurationProperties 활용

2025.04.23 - [[Gena Co.] Internship Project/GENA Labeling Tool] - (25.04.23) Spring Security 인증 인가를 통한 Login 기능 구현 & Token 재발급 구현

 

(25.04.23) Spring Security 인증 인가를 통한 Login 기능 구현 & Token 재발급 구현

2025.03.20 - [[Gena Co.] Internship Project/GENA Labeling Tool] - Gena Labeling Tool 개발기 : 기획부터 PoC 까지 Gena Labeling Tool 개발기 : 기획부터 PoC 까지안녕하세요, 저는 Gena Co. 인턴 김현진(Andrew) 입니다. Gena에서 t

andrew75313.tistory.com

 

기존의 Gena Labelling Tool의 JWT 를 통한 인증 인가 방식을 도입하면서 

실제로 툴을 활용할 개발자들이 변수를 통해 해당 JWT를 커스텀할 수 있도록 하는 방법을 고안하고자 했다.

 

이전의 Credential 부분에 있어서 Spring Security를 활용중 Spring Boot 의 @Value 를 활용했지만,

JWT 설정 값들을 application 에서 한번에 설정할 수 있도록

여러 값들을 안전하게 한번에 설정할 수 있도록 

하기 위해 Spring 문서를 찾아보면서 

ConfigurationProperties 을 적용을 했다.


적용 상황 : JwtUtil

  • JWT 를 생성하는데 활용할 JwtUtil 클래스에서, JWT 시크릿키, 토큰 별 유효시간 등 값을 환경마다 지정할 수 있게 설정에서 다룰 필요가 있음

@Value

  • 빠르고 간편하게, 속성 파일의 값 즉, application 에서도 값을 생성자, 메서드 등에 직접적으로 주입할 수 있는 Annotation
  • 직접 직관적으로 환경변수로 지정을 할 수도 있음

기존 프로젝트에서 구성한 JwtUtil

@Component
public class JwtUtil {
...
    @Value("${JWT_SECRET_KEY}")
    private String secretKey;
    
    ...

    @PostConstruct
    public void init() {
        byte[] bytes = Base64.getDecoder().decode(secretKey);
        key = Keys.hmacShaKeyFor(bytes);
    }
    
    ...
  • 기존 프로젝트에서의 JWT SECRET KEY를 외부 환경변수에서(env)에서 직접적으로 secretKey 라는 필드에 직접적으로 지정을 한 상태

→ Github Actions 를 통한 CI/CD 과정에서, application.yml 에서 설정한 변수가 아니었기 때문에, application.yml만 보고 JWT_SECRET_KEY 설정을 놓칠 경우 Application 자체가 돌아가지 않는 이슈가 있었음

  • 지정한 대상에만 적용하기 때문에, 반복해서 사용할 경우 클래스마다 설정을 해줘야
  • 사용자가 잘못된 타입으로 지정(int 값인데, 너무 큰 숫자를 변수로 설정 등), 오타 등 컴파일에서야 해당 오류를 알 수 있는 단점

  단점을 보완할 수 있을까?

@ConfigurationProperties

  • Spring Boot에서 application에서의 설정값들을 그룹화하여 구조화된 방식으로 주입
    • Java 객체 Pojo로 바인딩=매핑 하는 방식

application.yml

jwt:
  secret-key: ${JWT_SECRET_KEY}
  access-token-time: ${JWT_ACCESS_TOKEN_TIME}
  refresh-token-time: ${JWT_REFRESH_TOKEN_TIME}
  • Spring Boot 기준으로 application.yml에서 JWT 설정값을 따로 관리하기 위해 위와 같이 환경변수로 설정할 수 있도록 세팅

→ SpringBoot 실행에 있어서의 설정값이 아닌, 실제 로직 코드에서 활용할 수 있는 수단인 @ConfigurationProperties를 @Value 대신 활용해야함

JwtProperties

@Component
@ConfigurationProperties(prefix = "jwt")
@Getter
@Setter
public class JwtProperties {
    private String secretKey;
    private long accessTokenTime;
    private long refreshTokenTime;
}
  • ListMapNested Object 등 복잡한 타입도 applcation의 설정 이름을 맞춰 매핑이 가능
  • Getter Setter 를 꼭 설정해서, 적용하고 활용할 수 있도록 해야함

새롭게 바꾼 JwtUtil

@Component
@RequiredArgsConstruor
public class JwtUtil {

    private final JwtProperties jwtProperties;

...

    @PostConstruct
    public void init() {
        byte[] bytes = Base64.getDecoder().decode(jwtProperties.getSecretKey());
        key = Keys.hmacShaKeyFor(bytes);
    }

    public String createAccessToken(User user) {
        Date date = new Date();

        return BEARER_PREFIX +
                Jwts.builder()
                        .setSubject(user.getId().toString())
                        .claim(AUTHORIZATION_KEY, user.getRole())
                        .setExpiration(new Date(date.getTime() + jwtProperties.getAccessTokenTime()))
                        .setIssuedAt(date)
                        .signWith(key, signatureAlgorithm)
                        .compact();
    }

    public String createRefreshToken(User user) {
        Date date = new Date();

        return BEARER_PREFIX +
                Jwts.builder()
                        .setSubject(user.getId().toString())
                        .claim(AUTHORIZATION_KEY, user.getRole())
                        .setExpiration(new Date(date.getTime() + jwtProperties.getRefreshTokenTime()))
                        .setIssuedAt(date)
                        .signWith(key, signatureAlgorithm)
                        .compact();
    ...
  • 따라서 그냥 JwtProperties 클래스를 생성자 주입을 하게 된다면, get 메서드를 통해서 바로 사용할 수 있음
    • ConfigurationProperties 클래스가 일종의 중간 역할

중첩 클래스를 바인딩해서 사용하기 예시)

mail:
  host: smtp.example.com
  port: 587
  auth:
    username: myemail@example.com
    password: secret
@Component
@ConfigurationProperties(prefix = "mail")
@Getter
@Setter
public class MailProperties {
    private String host;
    private int port;
    private Auth auth;

		@Getter
    @Setter
    public static class Auth {
        private String username;
        private String password;
    }

    ...
}
  • 위처럼 여러 중첩 클래스를 설정값 처럼 똑같이 매핑해서 만들 수 이씅ㅁ
    • MailProperties.getAuth.getUsername 처럼 활용할 수 있음

@Value와 비교

  @Value @ConfigurationProperties
설정 개수 소수, 여러개 다수, 그룹
타입 지원 제한적 ListMap, 객체 등 맞춰서 설정 가능
코드 구조 흩어짐, 한번에 파악 어려움 정리된 클래스
타입 안전 낮음 (문자열 기반) 높음 (객체 바인딩)
복잡한 구조 불가(매번 반복) 가능(중첩 클래스 등)

참고

https://docs.spring.io/spring-boot/appendix/application-properties/index.html

 

Common Application Properties :: Spring Boot

 

docs.spring.io