티스토리 뷰
OAuth 2.0 with Spring Security (3) - 클라이언트 어플리케이션 구성하는 방법
JStack 2024. 11. 11. 22:48이전 글: https://gojs.tistory.com/61
OAuth 2.0 with Spring Security (2) - 추가적인 로그인 설정
https://gojs.tistory.com/60 OAuth 2.0 with Spring Security (1) - 기본 로그인 구현하기최근 프로젝트들의 경향을 살펴보면 자체 데이터를 기반으로 인증 로직을 구현하기보다는 대형 플랫폼의 인증 시스템을
gojs.tistory.com
OAuth 2.0 클라이언트는 아래와 같은 기능들을 제공한다.
- 인가 코드
- 리프레쉬 토큰
- 클라이언트 자격증명
- 리소스 소유자 비밀번호 자격증명
- JWT
- 토큰 교환
@Configuration
@EnableWebSecurity
public class OAuth2ClientSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Client(oauth2 -> oauth2
.clientRegistrationRepository(this.clientRegistrationRepository())
.authorizedClientRepository(this.authorizedClientRepository())
.authorizedClientService(this.authorizedClientService())
.authorizationCodeGrant(codeGrant -> codeGrant
.authorizationRequestRepository(this.authorizationRequestRepository())
.authorizationRequestResolver(this.authorizationRequestResolver())
.accessTokenResponseClient(this.accessTokenResponseClient())
)
);
return http.build();
}
}
위 코드와 같이 HttpSecurity.oauth2Client() DSL은 OAuth 2.0 클라이언트의 핵심 컴포넌트를 커스텀할 수 있는 옵션들을 제공한다.
또한 HttpSecurity.oauth2Client().authorizationCodeGrant()는 인가 코드 증명을 커스텀할 수 있도록 한다.
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManger =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
OAuth2AuthorizedClientManager는 OAuth2AuthorizedClientProvider와 협력하여 OAuth 2.0 클라이언트의 인증을 관리하는 책임을 가진다.
위 코드를 기준으로 OAuth2AuthorizedClientProvider는 인가코드, 리프레쉬 토큰, 클라이언트 자격증명, 비밀번호의 증명 타입을 가진다.
위의 두 예시와 같이 OAuth 2.0 클라이언트를 설정할 수 있으며, 이 때 사용되는 핵심 인터페이스와 클래스를 알아보자.
ClientRegistration
ClientRegistration은 OAuth 2.0 또는 OpenID Connect 1.0 제공자에 등록된 클라이언트를 표현한다.
public final class ClientRegistration {
private String registrationId;
private String clientId;
private String clientSecret;
private ClientAuthenticationMethod clientAuthenticationMethod;
private AuthorizationGrantType authorizationGrantType;
private String redirectUri;
private Set<String> scopes;
private ProviderDetails providerDetails;
private String clientName;
public class ProviderDetails {
private String authorizationUri;
private String tokenUri;
private UserInfoEndpoint userInfoEndpoint;
private String jwkSetUri;
private String issuerUri;
private Map<String, Object> configurationMetadata;
public class UserInfoEndpoint {
private String uri;
private AuthenticationMethod authenticationMethod;
private String userNameAttributeName;
}
}
}
ClientRegistration 클래스에서 가지는 필드들은 아래와 같은 상태를 의미한다.
- registrationId: ClientRegistraion의 ID
- clientId: 클라이언트의 ID
- clientSecret: 클라이언트의 secret
- clientAuthenticationMethod: 클라이언트가 제공자의 인증에 사용하는 메서드 (client_seret_basic, client_secret_post, client_key_jwt, none)
- authorizationGrantType: OAuth 2.0 인증 프레임워크에서 정의한 인증 부여 타입
- redirectUri: 유저 인증 후 인증 서버가 유저의 user-agent를 redirect할 등록된 클라이언트의 redirect uri
- scopes: 인증 요청 흐름 중 클라이언트가 요청할 정보의 범위 (openid, email, profile, ...)
- clientName: 클라이언트를 위해 사용할 이름
- authorizationUri: 인증 서버의 인증 엔드포인트 uri
- tokenUri: 인증 서버의 토큰 엔드포인트 uri
- jwkSetUri: 인증 서버로부터 JWK를 조회하는데 사용되는 uri
- issuerUri: OIDC나 OAuth 서버의 issuer 식별 uri
- configurationMetadata: OpenID 제공자 설정 정보
- UserInfoEndpoint.uri: 인가된 엔드 유저의 클레임이나 속성에 접근하기 위해 사용되는 uri
- UserInfoEndpoint.authenticationMethod: 유저 정보 엔드포인트로 토큰을 보낼 때 사용되는 인가 방식 (header, form, query)
- UserInfoEndpoint.userNameAttributeName: 유저 정보 중 이름이나 식별자에 해당하는 속성의 이름
ClientRegistrationRepository
ClientRegistrationRepository는 ClientRegistration을 가져오는 역할을 한다.
Spring Boot는 spring.seurity.oaut2.client.registraion.registraionId로부터 바인딩된 ClientRegistraion 인스턴스를 ClientRegistraionRepository 내에 저장한다.
기본적으로 구현된 클래스는 InMemoryClientRegistrationRepository이고 ApplicationContext에 빈 오브젝트로 등록하여 특정한 구현체를 설정할 수 있다.
@Controller
public class OAuth2ClientController {
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@GetMapping("/")
public String index() {
ClientRegistration clientRegistration =
clientRegistrationRepository.findByRegistrationId("okta");
...
return "index";
}
}
OAuth2AuthorizedClient
OAuth2AuthorizedClient 클래스는 인증된 클라이언트의 정보가 담기는 클래스이다.
OAuth2AuthorizedClientRepository는 OAuth2AuthorizedClient를 웹 요청에 따라 영속화하는 역할을 가졌으며 OAuth2AuthorizedClientService는 OAuth2AuthorizedClient를 어플리케이션 레벨에서 관리하는 역할을 가진다.
또한 이 두 클래스는 클라이언트의 OAuth2AccessToken을 찾을 수 있는 기능을 제공하여 보호된 자원에 대해 요청할 수 있도록 한다.
@Controller
public class OAuth2ClientController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@GetMapping("/")
public String index(Authentication authentication) {
OAuth2AuthorizedClient authorizedClient =
authorizedClientService.loadAuthorizedClient("okta", authentication.getName());
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "index";
}
}
OAuth2AuthorizedClientManager는 OAuth2AuthorizedClient의 관리 책임을 가지며 아래의 역할을 포함한다.
- OAuth2AuthorizedClientProvider를 사용하여 OAuth 2.0 클라이언트 인증
- OAuth2AuthorizedClientService와 OAuth2AuthorizedClientRepository를 사용하여 OAuth2AuthorizedClient 영속화
- OAuth 2.0 클라이언트가 성공적으로 인증되면 OAuth2AuthorizationSuccessHandler에게 위임
- OAuth 2.0 클라이언트가 인증에 실패하게되면 OAuth2AuthorizationFailurehandler에게 위임
OAuth2AuthorizedClientManager의 기본 구현체는 DefaultOAuth2AuthorizedClientManager이며 내부적으로 OAuth2AuthorizedClientProvider와 연관된다. OAuth2AuthorizedClientProvider는 컴포지트 패턴으로 구성되어 여러 개의 인가타입을 지원한다. 따라서 OAuth2AuthorizedClientProviderBuilder를 사용하여 authorization_code, refresh_token, client_credintials, password와 같은 인가 타입을 설정할 수 있다.
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManger.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
'공부 > Spring Security' 카테고리의 다른 글
OAuth 2.0 with Spring Security (2) - 추가적인 로그인 설정 (3) | 2024.10.27 |
---|---|
OAuth 2.0 with Spring Security (1) - 기본 로그인 구현하기 (0) | 2024.10.06 |
Spring Security 동작 원리 및 보안 기본 (0) | 2024.06.23 |