https://github.com/minnim1010/spring-security/tree/main/oauth2
| 구성 요소 이름 | 설명 |
|---|---|
| OAuth2ClientProperties | application.yml을 읽어 생성하는 OAuth2Client 관련 값들을 저장한 객체 |
| ClientRegistration | OAuth 2.0, OpenID Connect 1.0 Provider에 클라이언트를 등록할 때 필요한 값들을 저장한 객체, client_id, client_secret 등이 존재한다. |
| OAuth2ClientPropertiesRegistrationAdapter | 생성된 OAuth2ClientProperties들마다 ClientRegistration를 생성한다. |
| InMemoryClientRegistrationRepository | 생성된 ClientRegistration들을 저장한 Map 기반 InMemory 레포지토리 |
| AuthorizationRequestRepository | 인가 요청을 시작한 시점부터 인가 요청을 받는 시점까지 OAuth2AuthorizationRequest를 유지한다. |
| DefaultOAuth2UserService | 발급 받은 accessToken으로 리소스 서버에서 사용자 정보 요청을 보내고 응답을 받아온다. 일반적으로 상속하여 받아온 사용자 정보를 회원 DB에 저장한다. |
| OAuth2AuthenticationSuccessHandler | OAuth2 인증이 성공했을 때, 추가 작업을 수행한다. 일반적으로 로그인 토큰/세션을 발급한다. |
| OAuth2AuthenticationFailureHandler | OAuth2 인증이 실패했을 때, 추가 작업을 수행한다. |
| OAuth2AuthorizationRequestRedirectFilter | URI에서 registerId를 파싱하고 registerId에 맞는 권한 승인 코드 요청 URI로 리다이렉트하라는 응답을 만들어 보낸다. |
| OAuth2LoginAuthenticationFilter | 권한 서버에게 OAuth2 클라이언트 인증을 요청하여 accessToken을 받아오고, DefaultOAuth2UserService을 사용하여 사용자의 정보를 리소스 서버에서 가져온다. |

OAuth2ClientProperties 생성OAuth2ClientPropertiesRegistrationAdapter를 통해 OAuth2ClientProperties에서 각 OAuth2 server 마다 ClientRegistration 생성ClientRegistration 리스트를 InMemoryClientRegistrationRepository에 저장
클라이언트에게 GET /oauth2/authorization/google Request를 보낸다.
실제 요청 메시지
GET /oauth2/authorization/google 요청이 들어온 경우, OAuth2AuthorizationRequestRedirectFilter가 요청을 받아 URI에서 registerId인 "google"을 파싱하여 registerId에 맞는 권한 승인 코드 요청 URI로 리다이렉트하라는 응답을 만들어 보낸다.

현재 authorizationRequestRepository를 쿠키 기반으로 하였으므로, 쿠키에 request가 저장되어있음을 확인할 수 있다.
OAuth2AuthorizationRequestRedirectFilter는 /oauth2/authorization/{registrationId}로 들어온 요청을 처리한다.

167줄에서는 authorizationRequestResolver.resolve()로 OAuth2의 권한 승인 코드를 요청하는 request를 만든다.
멤버인 authorizationRequestResolver는 OAuth2AuthorizationRequestResolver 인터페이스, DefaultOAuth2AuthorizationRequestResolver 구현체이다.
DefaultOAuth2AuthorizationRequestResolver.resolve()는 registrationId에 따라 login에 해당하는 OAuth2AuthorizationRequest를 만들어 반환한다.




만들어진 OAuth2AuthorizationRequest은 다음과 같다.

169줄에서는 authorizationRedirectStrategy에 따라 리다이렉트 응답을 만든다.

170줄의 return으로 요청 처리를 마무리하고 응답을 보낸다.
권한 서버(구글)에게 GET accounts.google.com/o/oauth2/v2/auth? 요청을 보낸다.
파라미터는 state, response_type, client_id, scope, redirect_url이다.
state는 CSRF를 방어하기 위해 랜덤 문자열이다.
사용자가 구글에 로그인되어있지 않다면, 구글에 로그인하는 작업을 추가로 수행한다.

redirect_url의 파라미터에 "code" 파라미터가 추가되었음을 확인할 수 있다.
사용자가 클라이언트에 GET /login/oauth2/code/google? 요청을 보낸다.
파라미터는 state, code, scope이다.

/login/oauth2/code/* 요청이 들어오면 OAuth2LoginAuthenticationFilter가 요청을 처리한다.
OAuth2LoginAuthenticationFilter은 AbstractAuthenticationProcessingFilter를 상속한 클래스로, /login/oauth2/code/*로 들어오는 요청에 대해 OAuth2 로그인을 수행하고 사용자의 정보를 가져온다.

227줄에서 attemptAuthentication()으로 OAuth2 인증을 수행한다.


194~195줄에서는 권한 서버에게 OAuth2 클라이언트 인증을 요청하여 accessToken을 받아오고, accessToken을 사용하여 사용자의 정보를 리소스 서버에서 가져온다.
AuthenticationManager 구현체인 ProviderManager에는 다음과 같은 3개의 Provider들이 있다.

이 중 OAuth2LoginAuthenticationProvider.authenticate()는 다음과 같다.

106~109줄에서는 authorizationCodeAuthenticationProvider.authenticate()로 access Token을 발급 받아 저장한 authorizationCodeAuthenticationToken을 반환한다.

authorizationCodeAuthenticationProvider.authenticate()는 accessTokenResponseClient를 통해 토큰 발급을 요청하고 토큰을 받아온다.
accessTokenResponseClient의 request는 다음과 같다.

117~118줄에서는 클라이언트에 설정된 CustomOAuth2UserService.loadUser()를 사용해 사용자 정보를 받아온다.


회원 정보를 받아온 OAuth2User는 다음과 같다.

OAuth2LoginAuthenticationFilter.doFilter()의 successfulAuthentication
클라이언트에 설정된 CustomOAuth2UserService.loadUser()로 최초 로그인 시에는 회원 가입을, 아닐 시에는 로그인으로 처리한다.

25줄에서 updateOrSave()를 이용해 회원가입/로그인 로직을 확인할 수 있다.
커스텀한 OAuth2SuccessHandler의 onAuthenticationSuccess()로 사용자의 JWT토큰을 발급하고 로그인 성공 시 리다이렉트할 url로 리다이렉트한다.


JWT 인증과 url 파라미터로 token을 넘겨주는 방식으로 로그인을 구현했으므로, 토큰이 url 파라미터에 있음을 확인할 수 있다.