728x90
- 액세스 토큰을 사용해서 UserInfo 엔드포인트 요청으로 최종 사용자의 (리소스 소유자) 속성을 가져오며 OAuth2User 타입의 객체를 리턴한다
- 구현체로 DefaultOAuth2UserService 와 OidcUserService 가 제공된다
DefaultOAuth2UserService
- 표준 OAuth 2.0 Provider를 지원하는 OAuth2UserService 구현체다
- OAuth2UserRequest 에 Access Token 을 담아 인가서버와 통신 후 사용자의 속성을 가지고 온다
- 최종 OAuth2User 타입의 객체를 반환한다
OidcUserService
- OpenID Connect 1.0 Provider를 지원하는 OAuth2UserService 구현체다
- OidcUserRequest 에 있는 ID Token(OicdUserService를 통해 인증 시에는 이미 scope에 openId를 추가한 경우이다)을 통해 인증 처리를 하며 필요시 DefaultOAuth2UserService 를 사용해서 UserInfo 엔드포인트의 사용자 속성을 요청한다
- 최종 OidcUser 타입의 객체를 반환한다
흐름

- 1번 경우
- DefaultOAuth2UserService에 요청을 하면 DefaultOAuth2UserService가 /userinfo?access_token=${token}로 인가 서버에 요청을 해서 user정보를 조회한다.
- 2번 경우
- token을 scope가 openId로 요청을 해서 토큰을 받은 경우 client는 OidcUserService에 유저 정보를 요청한다.
- 이 경우, 인가 서버와 통신하지 않고 인증 처리를 한다.
- 3번 경우
- 필요한 경우 OidcService가 DefaultOAuth2UserSerive에게 유져정보를 요청해 유저 정보를 읽어올 수도 있다.
구조

- DefaultOAuth2UserService 은 OAuth2User 타입의 객체를 반환한다
- OidcUserService 은 OidcUser 타입의 객체를 반환한다
- OidcUserRequest 의 승인된 토큰(Access Token, 권한부여를 통과하였다)에 포함되어 있는 scope 값이 accessibleScopes 의 값 들중 하나 이상 포함되어 있을 경우 UserInfo 엔드 포인트를 요청한다
OAuth2User & OidcUser
스프링 시큐리티는 UserAttributes 및 ID Token Claims 을 집계&구성하여 OAuth2User 와 OidcUser 타입의 클래스를 제공한다
OAuth2User
- OAuth 2.0 Provider 에 연결된 사용자 주체를 나타낸다
- 최종 사용자의 인증에 대한 정보인 Attributes 를 포함하고 있으며 first name, middle name, last name, email, phone number, address 등으로 구성된다
- 기본 구현체는 DefaultOAuth2User 이며 인증 이후 Authentication 의 principal 속성에 저장된다
OidcUser
- OAuth2User 를 상속한 인터페이스이며 OIDC Provider 에 연결된 사용자 주체를 나타낸다
- 최종 사용자의 인증에 대한 정보인 Claims 를 포함하고 있으며 OidcIdToken 및 OidcUserInfo 에서 집계 및 구성된다
- 기본 구현체는 DefaultOidcUser 이며 DefaultOAuth2User 를 상속하고 있으며 인증 이후 Authentication 의 principal 속성에 저장된다
흐름

- OAuth2User 타입으로 인증처리가 될 경우
- /userinfo?access_token 으로 요청을 하고, 인가 서버가 Attributes에 사용자 정보를 담아 OAuth2User담아준다.
- OidcUser 타입으로 인증처리가 될 경우
- /token?scope=openid 로 이미 토큰을 발급을 받았으며, ID토큰에 user의 정보가 clams안에 숨겨져 있다.
- 후에 인증서버를 들리지 않고 유져 정보를 얻을 수 있는 이유는 이미 IDToken에 유저 정보가 존재하기 때문
구조

- OAuth 2.0 로그인을 통해 인증받은 최종 사용자의 Principal 에는 OAuth2User 혹은 OidcUser 타입의 객체가 저장된다
- 권한 부여 요청 시 scope 파라미터에 openid 를 포함했다면 OidcUser 타입의 객체가 생성되며 OidcUser 는 OidcUserInfo 와 idToken 을 가지고 있으며 최종 사용자에 대한 Claims 정보를 포함하고 있다
- OAuth2UserAuthority 는 인가서버로부터 수신한 scope 정보를 집계해서 권한정보를 구성한다
- OidcUser 객체를 생성할 때 ID 토큰이 필요한데 이 때 JSON 웹 토큰 (JWT)으로 된 ID 토큰은 JSON Web Signature (JWS)로 서명이 되어 있기 때문에 반드시 정해진 알고리즘에 의한 검증이 성공하면 OidcUser 객체를 생성 해야 한다.
TEST
@GetMapping("/user")
public OAuth2User user(String accessToken) {
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(
"keycloak");
OAuth2AccessToken oAuth2AccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, accessToken,
Instant.now(), Instant.MAX);
OAuth2UserRequest oAuth2UserRequest = new OAuth2UserRequest(clientRegistration, oAuth2AccessToken);
DefaultOAuth2UserService defaultOAuth2UserService = new DefaultOAuth2UserService();
OAuth2User oAuth2User = defaultOAuth2UserService.loadUser(oAuth2UserRequest);
return oAuth2User;
}
@GetMapping("/oidc")
public OAuth2User oidc(String accessToken, String idToken) {
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(
"keycloak");
OAuth2AccessToken oAuth2AccessToken = new OAuth2AccessToken(TokenType.BEARER, accessToken,
Instant.now(), Instant.MAX);
Map<String, Object> idTokenClaims = new HashMap<>();
idTokenClaims.put(IdTokenClaimNames.ISS, "http://localhost:8080/realms/oauth2");
idTokenClaims.put(IdTokenClaimNames.SUB, "OIDC0");
idTokenClaims.put("preferred_username", "user");
OidcIdToken oidcIdToken = new OidcIdToken(idToken, Instant.now(), Instant.MAX, idTokenClaims);
OidcUserRequest oidcUserRequest = new OidcUserRequest(clientRegistration, oAuth2AccessToken, oidcIdToken);
OidcUserService oidcUserService = new OidcUserService();
OAuth2User oAuth2User = oidcUserService.loadUser(oidcUserRequest);
return oAuth2User;
}
- 실제로는 이러한 일을 직접 하지는 않는다 -> 과정을 보기 위해 test로 진행
- /user로 접근했을 때는 파라미터로 accesstoken을 주며, scope에 openId가 포함되어 있지 않은 상태로 토큰을 발급받은 상태여야 한다.
- /oidc로 접근했을 때는 파라미터로 accesstoken과 idToken을 주며, scope에 openId를 포함시켜 idToken을 발급받아야 하며, idToken안에 내부적으로 유저 정보들이 포함되어 있으므로 인증서버를 통해 유저 정보를 읽어오는 과정이 생략된다.
728x90
'스프링 시큐리티 OAuth2 > OAuth2LoginConfigurer 초기화 이해' 카테고리의 다른 글
| OAuth2 로그인 구현 - OpenID Connect 로그아웃 (0) | 2023.01.23 |
|---|---|
| OAuth2 로그인 구현 - UserInfo 엔드포인트 요청하기 (0) | 2023.01.22 |
| OAuth2 로그인 구현 - Access Token 교환하기 (0) | 2023.01.17 |
| OAuth2 로그인 구현 - Authorization Code 요청하기 (0) | 2023.01.17 |
| OAuth2 로그인 구현 - OAuth 2.0 Login Page 생성 (0) | 2023.01.16 |