728x170
해당 글에서는 Spring Boot Configuration Processor를 활용하여서 외부 설정 소스 파일(yaml/yml, properties)을 불러오는 다양한 방법에 대해 알아봅니다
1) spring-boot-configuration-processor
💡 spring-boot-configuration-processor
- Spring Boot 애플리케이션의 외부화된 구성 및 속성 파일에 정의된 속성에 대해 쉽게 접근하여 값을 가져오는 기능을 제공하는 라이브러리입니다.
- 해당 라이브러리에서 @ConfigurationProperties 어노테이션을 통해서 적용된 클래스(class), 레코드(record)를 분석하여 메타데이터를 생성합니다.
1. 주요 특징
특징 | 설명 |
타입 안전성 | 컴파일 시점에서 타입 오류를 감지하여 런타임 에러를 방지합니다. 설정 값의 타입이 명확히 정의되어 있어 잘못된 타입 사용을 미리 방지할 수 있습니다. |
유연성 | 다양한 형식(YAML/YML, Properties 등)의 설정 파일을 지원하며, 필요에 따라 동적으로 설정을 변경할 수 있습니다. |
계층 구조 | 복잡한 설정을 계층적으로 구성할 수 있어 관련 설정을 그룹화하고 구조화하여 관리할 수 있습니다. 이는 설정의 가독성과 유지보수성을 향상시킵니다. |
검증 | @Validated 어노테이션을 통해 설정 값의 유효성을 검사할 수 있습니다. 이를 통해 잘못된 설정 값이 애플리케이션에 주입되는 것을 방지할 수 있습니다. |
자동 완성 기능 | IDE에서 설정 파일 작성 시 자동 완성 기능을 제공합니다. 이는 개발자의 생산성을 높이고 설정 오류를 줄이는 데 도움을 줍니다. |
2. configuration-processor에서의 메타데이터(Meta Data)
💡 configuration-processor에서의 메타데이터(Meta Data)
- configuration-processor에서는 @ConfigurationProperties(클래스)를 통해서 클래스, 레코드를 분석하여 메타데이터를 자동으로 생성합니다.
- 이는 외부 설정 소스(yaml/yml, properties 파일 등)를 통해서 클래스의 멤버 변수와 매핑이 되어서 값이 설정이 됩니다.
💡 아래와 같은 oauth2.yml 파일이 있습니다.
spring:
security:
oauth2:
client:
# OAuth2 인증 제공자에 대한 설정 정보를 포함합니다.
provider:
kakao:
authorization-uri: https://kauth.kakao.com/oauth/authorize
💡 configuration-processor 설정을 통해 위에 yml 파일과 OAuth2ClientProperties 클래스가 매핑이 되며, 멤버 변수로 각각의 값이 매핑이 됩니다.
@ConfigurationProperties(prefix = "spring.security.oauth2.client")
public record OAuth2ClientProperties(ProviderProperties provider) {
public record ProviderProperties(ProviderConfig kakao) {
public record ProviderConfig(String authorizationUri) {
}
}
}
3. 메타데이터와 클래스-속성 파일 매핑의 관계
💡 메타데이터와 클래스-속성 파일 매핑의 관계
- 메타데이터는 클래스와 속성 파일 간의 "브리지" 역할을 하며, 매핑 과정의 정확성과 효율성을 크게 향상합니다.
1. 메타데이터 생성
- spring-boot-configuration-processor는 @ConfigurationProperties 어노테이션이 적용된 클래스를 분석하여 메타데이터를 자동으로 생성합니다.
2. 매핑 정보 제공
- 생성된 메타데이터는 클래스의 구조, 속성 이름, 타입 등의 정보를 포함하여 Spring Boot가 속성 파일과 클래스를 정확히 매핑할 수 있도록 돕습니다.
3. IDE 지원
- 메타데이터는 IDE에서 자동완성, 문서화, 유효성 검사 등의 기능을 제공하여 개발자가 속성 파일을 더 쉽고 정확하게 작성할 수 있게 합니다.
4. 런타임 바인딩
- Spring Boot는 이 메타데이터를 사용하여 런타임에 속성 파일의 값을 클래스의 필드에 정확하게 바인딩합니다.
4. spring-boot-configuration-processor 주요 어노테이션
주요 어노테이션 | 설명 |
@ConfigurationProperties | 외부 설정 파일의 속성을 자바 객체에 바인딩하는데 사용됩니다. 특정 접두사를 가진 속성들을 하나의 클래스에 매핑할 수 있습니다. |
@EnableConfigurationProperties | @ConfigurationProperties가 적용된 클래스를 활성화하고 빈으로 등록합니다. 주로 메인 애플리케이션 클래스나 설정 클래스에서 사용됩니다. |
@ConfigurationPropertiesScan | 지정된 패키지 내의 모든 @ConfigurationProperties 클래스를 스캔하고 빈으로 등록합니다. |
@ConstructorBinding | 생성자를 통한 바인딩을 활성화합니다. 불변 객체를 만들 때 유용하며, 모든 프로퍼티를 final로 선언할 수 있습니다. |
@DefaultValue | 프로퍼티의 기본값을 지정합니다. 설정 파일에 해당 프로퍼티가 없을 경우 이 값이 사용됩니다. |
@NestedConfigurationProperty | 중첩된 객체를 별도의 설정 클래스로 분리할 때 사용합니다. 복잡한 구조의 설정을 관리하는데 유용합니다. |
@Validated | 설정 클래스에 대한 유효성 검사를 활성화합니다. |
2) spring-boot-configuration-processor 초기 설정 및 기존 데이터 확인
1. 의존성 라이브러리 추가
dependencies {
implementation "org.springframework.boot:spring-boot-configuration-processor" // Spring Boot Configuration Processor
}
Maven Repository: org.springframework.boot » spring-boot-configuration-processor
2. 불러 올 데이터 확인 : application.properties(yml)
💡불러 올 데이터 확인 : application.properties(yml)
- yml 파일 형태로 구성이 되어 있으며 Spring Boot OAuth 2.0 기반의 카카오, 네이버 로그인에 대한 설정 정보입니다.
spring:
security:
oauth2:
client:
# OAuth2 인증 제공자에 대한 설정 정보를 포함합니다.
provider:
kakao:
authorization-uri: <https://kauth.kakao.com/oauth/authorize>
token-uri: <https://kauth.kakao.com/oauth/token>
user-info-uri: <https://kapi.kakao.com/v2/user/me>
user-name-attribute: id
naver:
authorization-uri: <https://nid.naver.com/oauth2.0/authorize>
token-uri: <https://nid.naver.com/oauth2.0/token>
user-info-uri: <https://openapi.naver.com/v1/nid/me>
user-name-attribute: id
# 클라이언트 애플리케이션(Spring Boot)에 대한 설정을 포함합니다.
registration:
kakao:
client-id: xx
client-secret: xx
redirect-uri:
authorization-grant-type: authorization_code
client-authentication-method: POST
client-name: kakao
scope:
- name
- profile_nickname
- account_email
naver:
client-id: xx
client-secret: xx
redirect-uri:
authorization-grant-type: authorization_code
client-authentication-method: client_secret_post
client-name: naver
scope:
- nickname
- email
- profile_image
3. 조회 방법 확인 : @value
💡조회 방법 확인 : @value
- 기존의 @Value 어노테이션을 통해 properties 파일을 가져왔습니다. 이는 타입의 안정성도 보장이 되지 않고, 값을 찾는데 복잡하다는 문제점이 있었습니다.
- 이를 해결하기 위한 방법으로 properties 파일을 spring-boot-configuration-processor를 활용하여서 객체 형태로 구성합니다.
어노테이션 | 설명 |
@Value | Spring Framework에서 제공하는 어노테이션으로, 외부 설정 파일(properties, YAML 등)의 값을 Spring 빈의 필드나 메서드 파라미터에 주입하는 데 사용됩니다. 주로 단일 값을 주입할 때 사용되며, 표현식을 통해 복잡한 값도 주입할 수 있습니다. |
@Value("${spring.security.oauth2.client.provider.kakao.token-uri}")
private String KAKAO_TOKEN_URL = "";
@Value("${spring.security.oauth2.client.provider.kakao.user-info-uri}")
private String KAKAO_USER_INFO_URL = "";
@Value("${spring.security.oauth2.client.provider.kakao.user-name-attribute}")
private String KAKAO_USER_NAME_ATTRIBUTE = "";
@Value("${spring.security.oauth2.client.registration.kakao.client-id}")
private String KAKAO_CLIENT_ID = "";
@Value("${spring.security.oauth2.client.registration.kakao.client-secret}")
private String KAKAO_CLIENT_SECRET = "";
@Value("${spring.security.oauth2.client.registration.kakao.redirect-uri}")
private String KAKAO_REDIRECT_URL = "";
@Value("${spring.security.oauth2.client.provider.naver.token-uri}")
private String NAVER_TOKEN_URL = "";
@Value("${spring.security.oauth2.client.provider.naver.user-info-uri}")
private String NAVER_USER_INFO_URL = "";
@Value("${spring.security.oauth2.client.provider.naver.user-name-attribute}")
private String NAVER_USER_NAME_ATTRIBUTE = "";
@Value("${spring.security.oauth2.client.registration.naver.client-id}")
private String NAVER_CLIENT_ID = "";
@Value("${spring.security.oauth2.client.registration.naver.client-secret}")
private String NAVER_CLIENT_SECRET = "";
@Value("${spring.security.oauth2.client.registration.naver.redirect-uri}")
private String NAVER_REDIRECT_URL = "";
3) spring-boot-configuration-processor 활용하기 : 생성자(Getter) 이용 방법
💡 spring-boot-configuration-processor 활용하기 : 생성자(Getter) 이용 방법
- 이 방식은 생성자를 통해 설정 값을 주입받는 방식입니다. 이는 불변성을 보장하며, 모든 필드가 final로 선언될 수 있습니다.
- 생성자를 통해 모든 필드가 초기화되므로, 누락된 설정 값을 쉽게 발견할 수 있습니다. 테스트하기 쉽고, 스프링의 생성자 주입 방식과 일관성이 있습니다.
1. OAuth2ClientProperties
💡OAuth2ClientProperties
- 아래와 같은 구성을 통해서 application.properties 또는 application.yml 파일의 설정을 타입 안전하게 자바 객체로 매핑할 수 있습니다. 이를 통해 설정 값에 쉽게 접근하고 관리할 수 있습니다.
- @ConfigurationProperties 어노테이션을 통해 'spring.security.oauth2.client' 접두사로 시작하는 설정을 매핑합니다.
- 구성은 크게 ProviderProperties와 RegistrationProperties 두 개의 내부 클래스로 구성되어 있습니다.
- 각 내부 클래스는 카카오와 네이버에 대한 설정을 포함합니다.
- ProviderConfig 클래스는 인증 제공자의 URI 정보를 포함합니다.
- RegistrationConfig 클래스는 클라이언트 ID, 비밀키, 리다이렉트 URI 등의 클라이언트 등록 정보를 포함합니다.
어노테이션 | 설명 |
@ConfigurationProperties | 외부 설정 파일의 속성을 자바 객체에 바인딩하는데 사용됩니다. 특정 접두사를 가진 속성들을 하나의 클래스에 매핑할 수 있습니다. |
package com.adjh.springbootoauth2.config.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
@Setter
@ConfigurationProperties(prefix = "spring.security.oauth2.client")
public class OAuth2ClientProperties {
private Map<String, Provider> provider = new HashMap<>();
private Map<String, Registration> registration = new HashMap<>();
@Getter
@Setter
public static class Provider {
private String authorizationUri;
private String tokenUri;
private String userInfoUri;
private String userNameAttribute;
}
@Getter
@Setter
public static class Registration {
private String clientId;
private String clientSecret;
private String redirectUri;
private String authorizationGrantType;
private String clientAuthenticationMethod;
private String clientName;
private List<String> scope;
}
}
2. SpringBoot3SecurityOauth2Application
💡 SpringBoot3SecurityOauth2Application
- Main Class 내에서 구성한 properties 파일을 스캔합니다. 이는 단건 클래스로 조회 및 등록을 하거나 혹은 패키지 경로에 따라 여러 클래스를 조회 및 등록하는 방법이 있습니다.
- @EnableConfigurationProperties(OAuth2ClientProperties.class)의 경우는 OAuth2ClientProperties 클래스 내에서 구성한 Properties 파일을 매핑합니다.
- 그리고 @ConfigurationPropertiesScan("com.adjh.springbootoauth2.config.properties") 경우에는 “com.adjh.springbootoauth2.config.properties” 패키지 내의 properties를 매핑한 파일들을 모두 스캔합니다.
어노테이션 | 설명 |
@EnableConfigurationProperties | @ConfigurationProperties가 적용된 클래스를 활성화하고 빈으로 등록합니다. 주로 메인 애플리케이션 클래스나 설정 클래스에서 사용됩니다. |
@ConfigurationPropertiesScan | 지정된 패키지 내의 모든 @ConfigurationProperties 클래스를 스캔하고 빈으로 등록합니다. |
package com.adjh.springbootoauth2;
import com.adjh.springbootoauth2.config.properties.OAuth2ClientProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
// 단건 클래스로 조회 및 등록
@EnableConfigurationProperties(OAuth2ClientProperties.class)
// or
// 패키지 경로에 따라 여러 클래스 조회 및 등록
@ConfigurationPropertiesScan("com.adjh.springbootoauth2.config.properties")
public class SpringBoot3SecurityOauth2Application {
public static void main(String[] args) {
SpringApplication.run(SpringBoot3SecurityOauth2Application.class, args);
}
}
3. Properties 파일 호출
💡Properties 파일 호출
- 아래와 같이 프로퍼티의 값을 객체 내애서 불러와서 클래스 내에서 사용이 됩니다. 해당 방식에서는 특히 이전에 @Getter를 통해서 .get() 메서드를 통해 데이터를 호출해 옵니다.
- 또한, init() 메서드에 @PostConstruct 어노테이션이 붙어있어, 빈 생성 후 자동으로 실행되며, OAuth2ClientProperties 객체로부터 각 설정 값을 가져와 필드에 할당합니다.
@Slf4j
@Service("OAuth2ServiceImpl")
public class OAuth2ServiceImpl implements OAuth2Service {
private final RestTemplateConfig restTemplateConfig;
private OAuth2ClientProperties oAuth2ClientProperties;
public OAuth2ServiceImpl(RestTemplateConfig restTemplateConfig, OAuth2ClientProperties oAuth2ClientProperties) {
this.restTemplateConfig = restTemplateConfig;
this.oAuth2ClientProperties = oAuth2ClientProperties;
}
private String KAKAO_TOKEN_URL;
private String KAKAO_USER_INFO_URL;
private String KAKAO_USER_NAME_ATTRIBUTE;
private String KAKAO_CLIENT_ID;
private String KAKAO_CLIENT_SECRET;
private String KAKAO_REDIRECT_URL;
private String NAVER_TOKEN_URL;
private String NAVER_USER_INFO_URL;
private String NAVER_USER_NAME_ATTRIBUTE;
private String NAVER_CLIENT_ID;
private String NAVER_CLIENT_SECRET;
private String NAVER_REDIRECT_URL;
@PostConstruct
public void init() {
KAKAO_TOKEN_URL = oAuth2ClientProperties.getProvider().getKakao().getTokenUri();
KAKAO_USER_INFO_URL = oAuth2ClientProperties.getProvider().getKakao().getUserInfoUri();
KAKAO_USER_NAME_ATTRIBUTE = oAuth2ClientProperties.getProvider().getKakao().getUserNameAttribute();
KAKAO_CLIENT_ID = oAuth2ClientProperties.getRegistration().getKakao().getClientId();
KAKAO_CLIENT_SECRET = oAuth2ClientProperties.getRegistration().getKakao().getClientSecret();
KAKAO_REDIRECT_URL = oAuth2ClientProperties.getRegistration().getKakao().getRedirectUri();
NAVER_TOKEN_URL = oAuth2ClientProperties.getProvider().getNaver().getTokenUri();
NAVER_USER_INFO_URL = oAuth2ClientProperties.getProvider().getNaver().getUserInfoUri();
NAVER_USER_NAME_ATTRIBUTE = oAuth2ClientProperties.getProvider().getNaver().getUserNameAttribute();
NAVER_CLIENT_ID = oAuth2ClientProperties.getRegistration().getNaver().getClientId();
NAVER_CLIENT_SECRET = oAuth2ClientProperties.getRegistration().getNaver().getClientSecret();
NAVER_REDIRECT_URL = oAuth2ClientProperties.getRegistration().getNaver().getRedirectUri();
}
@Override
public LoginKakaoReqDto kakaoLogin(LoginKakaoReqDto loginKakaoReqDto) {
log.debug("KAKAO_TOKEN_URL: {}", KAKAO_TOKEN_URL);
log.debug("KAKAO_USER_INFO_URL: {}", KAKAO_USER_INFO_URL);
log.debug("KAKAO_USER_NAME_ATTRIBUTE: {}", KAKAO_USER_NAME_ATTRIBUTE);
log.debug("KAKAO_CLIENT_ID: {}", KAKAO_CLIENT_ID);
log.debug("KAKAO_CLIENT_SECRET: {}", KAKAO_CLIENT_SECRET);
log.debug("KAKAO_REDIRECT_URL: {}", KAKAO_REDIRECT_URL);
log.debug("NAVER_TOKEN_URL: {}", NAVER_TOKEN_URL);
log.debug("NAVER_USER_INFO_URL: {}", NAVER_USER_INFO_URL);
log.debug("NAVER_USER_NAME_ATTRIBUTE: {}", NAVER_USER_NAME_ATTRIBUTE);
log.debug("NAVER_CLIENT_ID: {}", NAVER_CLIENT_ID);
log.debug("NAVER_CLIENT_SECRET: {}", NAVER_CLIENT_SECRET);
log.debug("NAVER_REDIRECT_URL: {}", NAVER_REDIRECT_URL);
}
}
4. 결과 확인
💡 결과 확인
- 위와 같이 구성한 결과를 아래와 같이 출력하였습니다.
4) spring-boot-configuration-processor 활용하기 : 레코드 타입
💡 spring-boot-configuration-processor 활용하기 : 레코드 타입
- Java 14 버전에 추가된 레코드 타입을 사용하여 설정 값을 매핑하는 방식입니다.
- 이는 생성자 타입보다 간결한 코드로 설정 값을 정의하고 접근할 수 있습니다.@Getter 어노테이션을 통한 메서드 대신에 필드 이름을 직접 메서드처럼 호출을 한다는 장점이 있습니다.
Guide to @ConfigurationProperties in Spring Boot | Baeldung
1. OAuth2ClientProperties
💡 OAuth2ClientProperties
- @ConfigurationProperties 어노테이션을 사용하여 'spring.security.oauth2.client' 접두사로 시작하는 설정을 매핑합니다.
- 레코드(record) 타입을 사용하여 불변성을 보장하고 간결한 코드를 작성했습니다.
- OAuth2ClientProperties 클래스는 ProviderProperties와 RegistrationProperties 두 개의 내부 레코드로 구성됩니다.
- ProviderProperties는 카카오와 네이버의 인증 제공자 설정을 포함합니다.
- RegistrationProperties는 카카오와 네이버의 클라이언트 등록 정보를 포함합니다.
- 각 설정에는 인증 URI, 토큰 URI, 사용자 정보 URI, 클라이언트 ID, 비밀키, 리다이렉트 URI 등의 정보가 포함됩니다.
어노테이션 | 설명 |
@ConfigurationProperties | 외부 설정 파일의 속성을 자바 객체에 바인딩하는데 사용됩니다. 특정 접두사를 가진 속성들을 하나의 클래스에 매핑할 수 있습니다. |
package com.adjh.springbootoauth2.config.properties;
import lombok.Getter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
@ConfigurationProperties(prefix = "spring.security.oauth2.client")
public record OAuth2ClientProperties(ProviderProperties provider, RegistrationProperties registration) {
public record ProviderProperties(ProviderConfig kakao, ProviderConfig naver) {
public record ProviderConfig(String authorizationUri, String tokenUri, String userInfoUri, String userNameAttribute) {
}
}
public record RegistrationProperties(RegistrationConfig kakao, RegistrationConfig naver) {
public record RegistrationConfig(String clientId, String clientSecret, String redirectUri, String authorizationGrantType, String clientAuthenticationMethod,
String clientName, List<String> scope) {
}
}
}
2. SpringBoot3SecurityOauth2Application
💡 SpringBoot3SecurityOauth2Application
- Main Class에 @EnableConfigurationProperties을 통해서 Properties 클래스를 등록해 줍니다. 이는 Spring 애플리케이션 내에 컨텍스트를 등록하기 위해 수행합니다.
어노테이션 | 설명 |
@EnableConfigurationProperties | @ConfigurationProperties가 적용된 클래스를 활성화하고 빈으로 등록합니다. 주로 메인 애플리케이션 클래스나 설정 클래스에서 사용됩니다. |
@ConfigurationPropertiesScan | 지정된 패키지 내의 모든 @ConfigurationProperties 클래스를 스캔하고 빈으로 등록합니다. |
package com.adjh.springbootoauth2;
import com.adjh.springbootoauth2.config.properties.OAuth2ClientProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
// 단건 클래스로 조회 및 등록
@EnableConfigurationProperties(OAuth2ClientProperties.class)
// or
// 패키지 경로에 따라 여러 클래스 조회 및 등록
@ConfigurationPropertiesScan("com.adjh.springbootoauth2.config.properties")
public class SpringBoot3SecurityOauth2Application {
public static void main(String[] args) {
SpringApplication.run(SpringBoot3SecurityOauth2Application.class, args);
}
}
3. Properties 파일 호출
💡 Properties 파일 호출
- 아래와 같이 프로퍼티의 값을 객체 내애서 불러와서 클래스 내에서 사용이 됩니다. 해당 방식에서는 특히 생성자 @Getter를 통한 .get() 메서드가 아닌 속성값을 통해 데이터를 호출해 옵니다.
- 또한, init() 메서드에 @PostConstruct 어노테이션이 붙어있어, 빈 생성 후 자동으로 실행되며, OAuth2ClientProperties 객체로부터 각 설정 값을 가져와 필드에 할당합니다.
@Slf4j
@Service("OAuth2ServiceImpl")
public class OAuth2ServiceImpl implements OAuth2Service {
private final RestTemplateConfig restTemplateConfig;
private OAuth2ClientProperties oAuth2ClientProperties;
public OAuth2ServiceImpl(RestTemplateConfig restTemplateConfig, OAuth2ClientProperties oAuth2ClientProperties) {
this.restTemplateConfig = restTemplateConfig;
this.oAuth2ClientProperties = oAuth2ClientProperties;
}
private String KAKAO_TOKEN_URL;
private String KAKAO_USER_INFO_URL;
private String KAKAO_USER_NAME_ATTRIBUTE;
private String KAKAO_CLIENT_ID;
private String KAKAO_CLIENT_SECRET;
private String KAKAO_REDIRECT_URL;
private String NAVER_TOKEN_URL;
private String NAVER_USER_INFO_URL;
private String NAVER_USER_NAME_ATTRIBUTE;
private String NAVER_CLIENT_ID;
private String NAVER_CLIENT_SECRET;
private String NAVER_REDIRECT_URL;
@PostConstruct
public void init() {
KAKAO_TOKEN_URL = oAuth2ClientProperties.provider().kakao().tokenUri();
KAKAO_USER_INFO_URL = oAuth2ClientProperties.provider().kakao().userInfoUri();
KAKAO_USER_NAME_ATTRIBUTE = oAuth2ClientProperties.provider().kakao().userNameAttribute();
KAKAO_CLIENT_ID = oAuth2ClientProperties.registration().kakao().clientId();
KAKAO_CLIENT_SECRET = oAuth2ClientProperties.registration().kakao().clientSecret();
KAKAO_REDIRECT_URL = oAuth2ClientProperties.registration().kakao().redirectUri();
NAVER_TOKEN_URL = oAuth2ClientProperties.provider().naver().tokenUri();
NAVER_USER_INFO_URL = oAuth2ClientProperties.provider().naver().userInfoUri();
NAVER_USER_NAME_ATTRIBUTE = oAuth2ClientProperties.provider().naver().userNameAttribute();
NAVER_CLIENT_ID = oAuth2ClientProperties.registration().naver().clientId();
NAVER_CLIENT_SECRET = oAuth2ClientProperties.registration().naver().clientSecret();
NAVER_REDIRECT_URL = oAuth2ClientProperties.registration().naver().redirectUri();
}
@Override
public LoginKakaoReqDto kakaoLogin(LoginKakaoReqDto loginKakaoReqDto) {
log.debug("KAKAO_TOKEN_URL: {}", KAKAO_TOKEN_URL);
log.debug("KAKAO_USER_INFO_URL: {}", KAKAO_USER_INFO_URL);
log.debug("KAKAO_USER_NAME_ATTRIBUTE: {}", KAKAO_USER_NAME_ATTRIBUTE);
log.debug("KAKAO_CLIENT_ID: {}", KAKAO_CLIENT_ID);
log.debug("KAKAO_CLIENT_SECRET: {}", KAKAO_CLIENT_SECRET);
log.debug("KAKAO_REDIRECT_URL: {}", KAKAO_REDIRECT_URL);
log.debug("NAVER_TOKEN_URL: {}", NAVER_TOKEN_URL);
log.debug("NAVER_USER_INFO_URL: {}", NAVER_USER_INFO_URL);
log.debug("NAVER_USER_NAME_ATTRIBUTE: {}", NAVER_USER_NAME_ATTRIBUTE);
log.debug("NAVER_CLIENT_ID: {}", NAVER_CLIENT_ID);
log.debug("NAVER_CLIENT_SECRET: {}", NAVER_CLIENT_SECRET);
log.debug("NAVER_REDIRECT_URL: {}", NAVER_REDIRECT_URL);
}
}
4. 결과 확인
💡 결과 확인
- 위와 같이 구성한 결과를 아래와 같이 출력하였습니다.
5) spring-boot-configuration-processor 활용하기 : 속성 분리
💡 spring-boot-configuration-processor 활용하기 : 속성 분리
- 호출부가 길어진다는 점이 있기에 좀 더 가시적으로 Properties 파일을 두 개로 분리하였습니다.
1. Provider 별 분리
💡 Provider 별 분리
- OAuth 2.0에서 kakao, naver가 동일한 형태의 값을 가지고 있기에 상위에 대해서 호출하고 kakao, naver 형태로 분리하는 형태로 구성하였습니다.
package com.adjh.springbootoauth2.config.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Getter
@Setter
@ConfigurationProperties(prefix = "spring.security.oauth2.client.provider")
public class OAuth2ProviderProperties {
private ProviderConfig kakao;
private ProviderConfig naver;
@Setter
@Getter
public static class ProviderConfig {
private String authorizationUri;
private String tokenUri;
private String userInfoUri;
private String userNameAttribute;
}
}
💡 Record 타입으로 구성
- 위와 동일하지만 다른 방식으로 .get() 형태를 사용하지 않고 가시적인 호출을 위해 Record 타입으로 구성하였습니다.
package com.adjh.springbootoauth2.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.security.oauth2.client.provider")
public record OAuth2ProviderProperties(ProviderConfig kakao, ProviderConfig naver) {
public record ProviderConfig(
String authorizationUri,
String tokenUri,
String userInfoUri,
String userNameAttribute
) {
}
}
2. Registration 별 분리
💡 Registration 별 분리
- OAuth 2.0에서 kakao, naver가 동일한 형태의 값을 가지고 있기에 상위에 대해서 호출하고 kakao, naver 형태로 분리하는 형태로 구성하였습니다.
package com.adjh.springbootoauth2.config.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
@Getter
@Setter
@ConfigurationProperties(prefix = "spring.security.oauth2.client.registration")
public class OAuth2RegistrationProperties {
private RegistrationConfig kakao;
private RegistrationConfig naver;
@Setter
@Getter
public static class RegistrationConfig {
private String clientId;
private String clientSecret;
private String redirectUri;
private String authorizationGrantType;
private String clientAuthenticationMethod;
private String clientName;
private List<String> scope;
}
}
💡 Record 타입으로 구성
- 위와 동일하지만 다른 방식으로 .get() 형태를 사용하지 않고 가시적인 호출을 위해 Record 타입으로 구성하였습니다.
package com.adjh.springbootoauth2.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
@ConfigurationProperties(prefix = "spring.security.oauth2.client.registration")
public record OAuth2RegistrationProperties(
RegistrationConfig kakao,
RegistrationConfig naver
) {
public record RegistrationConfig(
String clientId,
String clientSecret,
String redirectUri,
String authorizationGrantType,
String clientAuthenticationMethod,
String clientName,
List<String> scope
) {
}
}
3. Properties 파일 호출
💡Properties 파일 호출
- 아래와 같이 프로퍼티의 값을 객체 내에서 불러와서 클래스/레코드 내에서 사용이 됩니다. 해당 방식에서는 좀 더가시적으로 구성이 되었습니다.
3.1. 일반 클래스로 구성한 형태에서 호출
💡 일반 클래스로 구성한 형태에서 호출
- 구성한 클래스를 호출하여 각각의 값을 가져옵니다.
@Slf4j
@Service("OAuth2ServiceImpl")
public class OAuth2ServiceImpl implements OAuth2Service {
private final RestTemplateConfig restTemplateConfig;
private final OAuth2ClientProperties oAuth2ClientProperties;
private final OAuth2ProviderProperties oAuthProvider;
private final OAuth2RegistrationProperties oAuthRegistration;
public OAuth2ServiceImpl(RestTemplateConfig restTemplateConfig, OAuth2ClientProperties properties, OAuth2ProviderProperties oAuthProvider, OAuth2RegistrationProperties oAuthRegistration) {
this.restTemplateConfig = restTemplateConfig;
this.oAuth2ClientProperties = properties;
this.oAuthProvider = oAuthProvider;
this.oAuthRegistration = oAuthRegistration;
}
@Override
public LoginKakaoReqDto kakaoLogin(LoginKakaoReqDto loginKakaoReqDto) {
log.debug("KAKAO_TOKEN_URL: {}", oAuthProvider.getKakao().getTokenUri());
log.debug("KAKAO_USER_INFO_URL: {}", oAuthProvider.getKakao().getUserInfoUri());
log.debug("KAKAO_USER_NAME_ATTRIBUTE: {}", oAuthProvider.getKakao().getUserNameAttribute());
log.debug("KAKAO_CLIENT_ID: {}", oAuthRegistration.getKakao().getClientId());
log.debug("KAKAO_CLIENT_SECRET: {}", oAuthRegistration.getKakao().getClientSecret());
log.debug("KAKAO_REDIRECT_URL: {}", oAuthRegistration.getKakao().getRedirectUri());
log.debug("NAVER_TOKEN_URL: {}", oAuthProvider.getNaver().getTokenUri());
log.debug("NAVER_USER_INFO_URL: {}", oAuthProvider.getNaver().getUserInfoUri());
log.debug("NAVER_USER_NAME_ATTRIBUTE: {}", oAuthProvider.getNaver().getUserNameAttribute());
log.debug("NAVER_CLIENT_ID: {}", oAuthRegistration.getNaver().getClientId());
log.debug("NAVER_CLIENT_SECRET: {}", oAuthRegistration.getNaver().getClientSecret());
log.debug("NAVER_REDIRECT_URL: {}", oAuthRegistration.getNaver().getRedirectUri());
}
}
3.2. 레코드로 구성한 형태에서 호출
💡 레코드로 구성한 형태에서 호출
- get() 형태가 아닌 형태로 호출하기에 좀 더 명확하게 메서드를 이해하여 호출할 수 있습니다.
@Slf4j
@Service("OAuth2ServiceImpl")
public class OAuth2ServiceImpl implements OAuth2Service {
private final RestTemplateConfig restTemplateConfig;
private final OAuth2ClientProperties oAuth2ClientProperties;
private final OAuth2ProviderProperties oAuthProvider;
private final OAuth2RegistrationProperties oAuthRegistration;
public OAuth2ServiceImpl(RestTemplateConfig restTemplateConfig, OAuth2ClientProperties properties, OAuth2ProviderProperties oAuthProvider, OAuth2RegistrationProperties oAuthRegistration) {
this.restTemplateConfig = restTemplateConfig;
this.oAuth2ClientProperties = properties;
this.oAuthProvider = oAuthProvider;
this.oAuthRegistration = oAuthRegistration;
}
@Override
public LoginKakaoReqDto kakaoLogin(LoginKakaoReqDto loginKakaoReqDto) {
log.debug("KAKAO_TOKEN_URL: {}", oAuthProvider.kakao().tokenUri());
log.debug("KAKAO_USER_INFO_URL: {}", oAuthProvider.kakao().userInfoUri());
log.debug("KAKAO_USER_NAME_ATTRIBUTE: {}", oAuthProvider.kakao().userNameAttribute());
log.debug("KAKAO_CLIENT_ID: {}", oAuthRegistration.kakao().clientId());
log.debug("KAKAO_CLIENT_SECRET: {}", oAuthRegistration.kakao().clientSecret());
log.debug("KAKAO_REDIRECT_URL: {}", oAuthRegistration.kakao().redirectUri());
log.debug("NAVER_TOKEN_URL: {}", oAuthProvider.naver().tokenUri());
log.debug("NAVER_USER_INFO_URL: {}", oAuthProvider.naver().userInfoUri());
log.debug("NAVER_USER_NAME_ATTRIBUTE: {}", oAuthProvider.naver().userNameAttribute());
log.debug("NAVER_CLIENT_ID: {}", oAuthRegistration.naver().clientId());
log.debug("NAVER_CLIENT_SECRET: {}", oAuthRegistration.naver().clientSecret());
log.debug("NAVER_REDIRECT_URL: {}", oAuthRegistration.naver().redirectUri());
}
}
4. 결과 확인
💡 결과 확인
- 위와 같이 구성한 결과를 아래와 같이 출력하였습니다
오늘도 감사합니다😀
그리드형