Spring Security의 OAuth2 인증 동작 과정

박민지·2024년 5월 14일
1

Spring Security

목록 보기
4/4

https://github.com/minnim1010/spring-security/tree/main/oauth2

주요 구성 요소

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

동작 과정


OAuth2 Set up 과정

  1. application.yml파일을 읽어 OAuth2ClientProperties 생성
  2. OAuth2ClientPropertiesRegistrationAdapter를 통해 OAuth2ClientProperties에서 각 OAuth2 server 마다 ClientRegistration 생성
  3. ClientRegistration 리스트를 InMemoryClientRegistrationRepository에 저장

Oauth2 인증 과정


1. 사용자가 소셜 로그인 버튼을 클릭한다.

클라이언트에게 GET /oauth2/authorization/google Request를 보낸다.

실제 요청 메시지

2. 클라이언트가 사용자에 302 accounts.google.com/o/oauth2/v2/auth Response를 보낸다.

GET /oauth2/authorization/google 요청이 들어온 경우, OAuth2AuthorizationRequestRedirectFilter가 요청을 받아 URI에서 registerId인 "google"을 파싱하여 registerId에 맞는 권한 승인 코드 요청 URI로 리다이렉트하라는 응답을 만들어 보낸다.

현재 authorizationRequestRepository를 쿠키 기반으로 하였으므로, 쿠키에 request가 저장되어있음을 확인할 수 있다.

OAuth2AuthorizationRequestRedirectFilter/oauth2/authorization/{registrationId}로 들어온 요청을 처리한다.

167줄에서는 authorizationRequestResolver.resolve()로 OAuth2의 권한 승인 코드를 요청하는 request를 만든다.

멤버인 authorizationRequestResolverOAuth2AuthorizationRequestResolver 인터페이스, DefaultOAuth2AuthorizationRequestResolver 구현체이다.

DefaultOAuth2AuthorizationRequestResolver.resolve()는 registrationId에 따라 login에 해당하는 OAuth2AuthorizationRequest를 만들어 반환한다.

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

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

170줄의 return으로 요청 처리를 마무리하고 응답을 보낸다.


3. 사용자가 권한 승인 코드 발급 요청을 보낸다.

권한 서버(구글)에게 GET accounts.google.com/o/oauth2/v2/auth? 요청을 보낸다.
파라미터는 state, response_type, client_id, scope, redirect_url이다.

  • state는 CSRF를 방어하기 위해 랜덤 문자열이다.


4~5. 사용자가 구글에 로그인되어있지 않다면, 구글에 로그인한다.

사용자가 구글에 로그인되어있지 않다면, 구글에 로그인하는 작업을 추가로 수행한다.


6. 사용자가 구글 로그인에 성공하면, 권한 승인 코드를 발급하고 302 {권한 승인 코드 요청 파라미터의 redirect_url} Response를 보낸다.

redirect_url의 파라미터에 "code" 파라미터가 추가되었음을 확인할 수 있다.


7. 사용자가 클라이언트에 소셜 로그인을 요청한다.

사용자가 클라이언트에 GET /login/oauth2/code/google? 요청을 보낸다.
파라미터는 state, code, scope이다.


8~9. 클라이언트는 권한 서버에 accessToken 발급을 요청하고 응답 받는다.

/login/oauth2/code/* 요청이 들어오면 OAuth2LoginAuthenticationFilter가 요청을 처리한다.

OAuth2LoginAuthenticationFilterAbstractAuthenticationProcessingFilter를 상속한 클래스로, /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는 다음과 같다.


10~11. 클라이언트는 리소스 서버에 accessToken을 사용해 사용자 정보를 요청하고 응답 받는다.

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

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


12. 클라이언트는 사용자 정보를 기반으로 회원가입(최초 로그인 시)/로그인을 처리한다.

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

25줄에서 updateOrSave()를 이용해 회원가입/로그인 로직을 확인할 수 있다.


13. 클라이언트는 사용자에 인증 관련 토큰/세션을 발급하고, 포함하여 로그인 성공 url 리다이렉트 Response를 보낸다.

커스텀한 OAuth2SuccessHandleronAuthenticationSuccess()로 사용자의 JWT토큰을 발급하고 로그인 성공 시 리다이렉트할 url로 리다이렉트한다.

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


References

0개의 댓글