목차
- [이론] 스프링 시큐리티 1
- [OAuth] 스프링 시큐리티 OAuth
- [실습] 스프링 시큐리티 OAuth2 Login 1
- [실습] 스프링 시큐리티 OAuth2 Login 2
- [추가] 스프링 시큐리티 OAuth 로그인 처리 방법 1
- [추가] 스프링 시큐리티 OAuth 로그인 처리 방법 2
이전에 스프링 시큐리티를 이용하여 OAuth로그인을 해보았다
정보를 매핑, 유저 저장하는 것 외에 단순히 yml파일에 정보만을 작성했을 뿐인데 로그인이 진행된 것을 볼 수 있다
크게 2가지 작업으로 나누어 어떻게 이루어 진것인지를 알아볼 예정이다
- Setting
- Login 요청 처리
양이 좀 많으므로 우선 Setting부분을 알아보자
Setting
프로퍼티객체 생성
스프링은 기본적으로 수 많은 자동 설정들을 제공한다org.springframework.boot.autoconfigure.AutoConfiguration.imports
를 보게되면 144개나 되는 자동 설정정보들이 들어있는 것을 확인 할 수 있다
그 중 하나인 OAuth2ClientAutoConfiguration가 yml(혹은 properties)파일에 작성한 내용을 기반으로 registration과 provider를 등록을 해준다
@AutoConfiguration(before = SecurityAutoConfiguration.class)
@ConditionalOnClass({ EnableWebSecurity.class, ClientRegistration.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@Import({ OAuth2ClientRegistrationRepositoryConfiguration.class, OAuth2WebSecurityConfiguration.class })
public class OAuth2ClientAutoConfiguration {
}
@Import
에 OAuth2ClientRegistrationRepositoryConfiguration.class
를 타고 들어가면 다음과 같은 코드를 볼 수 있다
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OAuth2ClientProperties.class)
@Conditional(ClientsConfiguredCondition.class)
class OAuth2ClientRegistrationRepositoryConfiguration {
@Bean
@ConditionalOnMissingBean(ClientRegistrationRepository.class)
InMemoryClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
List<ClientRegistration> registrations = new ArrayList<>(
OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties).values());
return new InMemoryClientRegistrationRepository(registrations);
}
}
이 중 우리는 두가지를 눈여겨 볼 필요가 있다
@EnableConfigurationProperties(OAuth2ClientProperties.class)
InMemoryClientRegistrationRepository
Bean 등록
우선 첫번째 부터 확인 해보자
@EnableConfigurationProperties(OAuth2ClientProperties.class)
OAuth2ClientProperties 객체를 Property 파일을 통해 생성을 가능하게 해주는 것이다
- OAuth2ClientProperties.class
보기 쉽게 메소드는 모두 제거를 했다
우리가 작성했단 application-oauth.yml과 비교를 해보자
@ConfigurationProperties(prefix = "spring.security.oauth2.client")
public class OAuth2ClientProperties implements InitializingBean {
private final Map<String, Provider> provider = new HashMap<>();
private final Map<String, Registration> registration = new HashMap<>();
public static class Registration {
private String provider;
private String clientId;
private String clientSecret;
private String clientAuthenticationMethod;
private String authorizationGrantType;
private String redirectUri;
private Set<String> scope;
private String clientName;
}
public static class Provider {
private String authorizationUri;
private String tokenUri;
private String userInfoUri;
private String userInfoAuthenticationMethod;
private String userNameAttribute;
private String jwkSetUri;
private String issuerUri;
}
}
spring:
security:
oauth2:
client: # 이 부분까지 Prefix
registration: # 내부 static class인 Registration
google:
client-id:
client-secret:
redirect-uri: http://localhost:8080/login/oauth2/code/google
scope: email, profile
naver:
client-name: naver
client-id:
client-secret:
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8080/login/oauth2/code/naver
provider: # 내부 static class인 Provider
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: response
딱 봐도 비슷한 구조를 가진 것을 알 수 있다
@ConfigurationProperties
애노테이션은 우리가 설정 파일에 적어준정보를 객체 필드에 주입해여 생성해 준다
위 파일로 예시를 들면 registration에 google, naver를 key로 하위 값들을 value로 주입하는 것이다
InMemoryClientRegistrationRepository Bean 등록
다음으로는 위 설정 값인 OAuth2ClientProperties를 가지고 ClientRegistrationRepository를 등록하는것을 확인 해보자
- OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties)
public static Map<String, ClientRegistration> getClientRegistrations(OAuth2ClientProperties properties) {
Map<String, ClientRegistration> clientRegistrations = new HashMap<>();
properties.getRegistration().forEach((key, value) -> clientRegistrations.put(key,
getClientRegistration(key, value, properties.getProvider())));
return clientRegistrations;
}
private static ClientRegistration getClientRegistration(String registrationId,
OAuth2ClientProperties.Registration properties, Map<String, Provider> providers) {
Builder builder = getBuilderFromIssuerIfPossible(registrationId, properties.getProvider(), providers);
if (builder == null) {
builder = getBuilder(registrationId, properties.getProvider(), providers);
}
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
//매핑 작업
return builder.build();
}
getBuilderFromIssuerIfPossible()
메소드는 우리가 yml 설정 파일에 직접 작성한 provider(naver)를 통해서 ClientRegistration.Builder를 생성해준다
google과 같이 직접 작성하지 않은 Provider는 null을 반환하여 getBuilder()
를 타고 들어가 보면 아래와 같은 코드를 보게 된다
이 메소드에서 ProviderId(naver, google, github)를 통해서 CommonOAuth2Provider객체를 얻어온다
private static CommonOAuth2Provider getCommonProvider(String providerId) {
try {
return ApplicationConversionService.getSharedInstance().convert(providerId, CommonOAuth2Provider.class);
}
catch (ConversionException ex) {
return null;
}
}
CommonOAuth2Provider는 Spring Security에서 미리 등록해준Provider이다
우리가 yml파일에 google과 달리 naver에서 많은 정보를 적어준 이유가 Spring Security가 제공을 해주지 않기 때문이다
이렇게 yml에 적어준 registration을 통해 ClientRegistration
이 생성되고 해당 객체 리스트를 값으로 InMemoryClientRegistratinoRepository
가 bean으로 등록되어 로그인 요청 시 InMemoryClientRegistratinoRepository
에서 ClientRegistration
를 찾아 사용하게 되는것이다
정리
- application.yml을 통해
OAuth2ClientProperties
생성 OAuth2ClientProperties
를 가지고ClientRegistration
리스트를 가진InMemoryClientRegistratinoRepository
bean으로 등록
'공부기록 > Spring Security' 카테고리의 다른 글
Spring Security - 동적 권한 처리 (2) | 2023.03.29 |
---|---|
[추가] 스프링 시큐리티 OAuth 로그인 처리 방법 2 (0) | 2023.02.22 |
[실습] 스프링 시큐리티 OAuth2 Login 2 (2) | 2023.02.21 |
[실습] 스프링 시큐리티 OAuth2 Login 1 (0) | 2023.02.21 |
[이론] 스프링 시큐리티 OAuth (0) | 2023.02.20 |