ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 시큐리티가 OAuth 로그인을 처리하는 방법
    프로젝트/WebRTC 화상통화 프로젝트 2022. 8. 3. 00:01
    반응형

    (1) OAuth2.0이란?

    (2) Spring Security와 OAuth 2.0으로 로그인 구현하기(SpringBoot + React)

    (3) Spring Security OAuth 2.0 단위테스트

    (4) Spring Security가 OAuth 로그인을 처리하는 방법

     

    로그인 구현을 하고 나서 스프링 시큐리티가 많은 것을 추상화해준다고 느꼈습니다.

     

    실제로 어떻게 로그인을 처리해주는지 알아보고자 합니다.

     

     

    Config 설정

    스프링 시큐리티를 사용할 때 단지 application.properties 또는 application.yml에 client-id, cleint-secret 등의 정보만 적어줍니다.

     

    application.properties

    spring.security.oauth2.client.registration.google.client-id = 클라이언트 ID
    spring.security.oauth2.client.registration.google.client-secret= 클라이언트 보안 비밀
    spring.security.oauth2.client.registration.google.scope = profile, email

     

     

    어떻게 이런일이 가능할까요?

    스프링 시큐리티는 설정 파일에 적어준 정보들로 애플리케이션 실행 시 OAuth2ClientProperties 객체를 생성합니다.

     

    OAuth2ClientProperties

     

    둘이 매우 비슷한 구조인것을 알 수 있습니다.

    즉, 우리가 설정 파일에 적어준 정보들이 객체로 만들어져 활용됩니다.

     

    @ConfigurationProperties 어노테이션으로 설정 파일에 적어준 정보들을 OAuth2ClientProperties 필드에 주입하여 객체를 만듭니다.

     

     

    InMemoryRepository

    위의 설정을 통해 OAuth2ClientProperties를 빈으로 등록하고 내부 값들을 통해 OAuth2 서버 별로 ClientRegistration 객체를 만들어 InMemoryRepository에 저장합니다.

     

    이 과정이 OAuth2PropertiesRegistrationAdapter에서 이루어집니다.

    InMemoryRepository

     

    OAuth2ClientPropertiesRegistrationAdapter의 getClientRegistrations 메서드에서는 Registration 정보를 가져와서 clientRegistrations라는 Map 객체를 만듭니다.

     

    실제로 ClientRegistration을 만드는 과정은 밑의 getClientRegistration 메서드에서 일어납니다.

    OAuth2ClientPropertiesRegistrationAdapter

     

    이 코드를 분석하다보면 내부적으로 getCommonProvider 메서드를 호출합니다.

    이 메서드에서 providerId (github, google, naver)를 통해 CommonOAuth2Provider 객체를 얻어옵니다.

     

    getCommonProvider 메서드

     

    CommonOAuth2Provider는 자주 사용하는 OAuth2 server의 정보들을 미리 세팅해놓은 enum 클래스입니다.

    설정 정보를 적을 때 google과 달리 naver, kakao에서 많은 정보들을 적어준 이유가 CommonOAuth2Provider에 naver가 등록되어 있지 않기 때문입니다.

    enum 클래스

     

    이런 과정을 거쳐 OAuth2 서버마다 각각 ClientRegistration 객체가 생성되고 ClientRegistration 객체들을 Map에 담아 InMemoryClientRegistrationRepository에 저장합니다.

     

    실제로 로그인 요청이 온다면 

    spring security는 필터 체인을 통해 dispatcher servlet에 요청이 들어가지 전 여러 필터를 거쳐갑니다.

    그 중 OAuth2AuthorizationRequestRedirectFilter 에서 /oauth2/authorization/{registrationId}로 온 요청을 처리합니다.

     

    OAuth2AuthorizationRequestRedirectFilter는 OAuth2AuthozizationRequestResolver의 resolve 메서드를 호출합니다.

    이때 registrationId를 추출합니다. (구글, 카카오, 네이버)

     

     

     

    추출한 registrationId를 통해 InMemoryClientRegistrationRepository의 findByRegistrationID 메서드를 통해 설정에서 만들어진 ClientRegistration 객체를 가져옵니다.

     

    이후 OAuth2AuthorizationRequest 객체를 만듭니다.

     

    이제 OAuth2AuthorizationRequest 객체의 authorizationRequestUri로 redirect 요청을 보냅니다.

     

     

    그러면 우리는 아이디 비밀번호를 칠 수 있는 창으로 redirect 됩니다.

     

     

     

    사용자가 비밀번호를 입력하고 난 후

    OAuth2LoginAuthenticationFilter에서 처리합니다.

    registrationID를 통해 ClientRegistration 객체를 가져옵니다.

     

     

    이후에 OAuth2 server의 access token을 얻기 위한 authoziation coed를 OAuth2AuthorizationResponse 객체로 만들고  이를 통해 access token을 가져옵니다.

     

    access token가져오기

    ProviderManager의 authenticate 메서드를 통해 accesstoken을 가져오게 됩니다.

    이때 여러 Provider 중 OAuth2LoginAuthenticationProvider가 이 과정을 수행합니다.

     

    authenticate 메서드는 내부적으로 DefaultAuthorizationCodeTokenResponseClinet의 getTokenResponse 메서드를 호출합니다.

     

    DefaultAuthorizationCodeTokenResponseClient의 getTokenResponse 메서드에서 RestTemplate를 이용해 OAuth2 Server로 access token request를 보냅니다.

     

    access token으로 유저 정보 가져오기

    이제 토큰을 얻었고 OAuth2 server에서 유저 정보를 가져올 수 있습니다.

    userService의 loadUser() 메서드를 통해 유저 정보를 얻어옵니다.

    이 userService는 security config에서 설정해준 userService입니다.

     

    custom server를 만들었으며 loadUser 내부의 delegate.lodaUser 가 내부적으로 OAuth2 server로 유저 정보를 요청합니다.

     

    이때 delegate는 DefaultOAuth2UserService입니다.

     

    DefaultOAuth2UserService의 loadUser에서는 access token을 얻을 때와 같이 RestTemplate를 이용해서 OAuth2 server에 요청을 보냅니다.

     

     

    최종 정리

    1. 애플리케이션을 실행한다.
    2. application.yml파일을 읽어 OAuth2ClientProperties 생성한다.
    3. OAuth2ClientPropertiesRegistrationAdapter를 통해 OAuth2ClientProperties에서 각 OAuth2 server 마다 ClientRegistration 생성한다.
    4. ClientRegistration 리스트를 InMemoryClientRegistrationRepository에 저장한다.
    5. /oauth2/authorization/{registrationId}로 OAuth2 로그인 요청을 한다.
    6. 요청이 오면 OAuth2AuthorizationRequestRedirectFilter에서 registrationId에 따라 아이디 / 비밀번호를 입력할 수 있는 uri로 리다이렉트 시킨다.
    7. 아이디 / 비밀번호를 입력 후 얻을 수 있는 authorization code로 OAuth2LoginAuthenticationFilter에서 OAuth2 server와 소통한다.
      7-1. OAuth2LoginAuthenticationProvider 통해 access token을 얻어온다.
      7-2. OAuth2LoginAuthenticationProvider를 통해 access token을 이용해서 유저 정보를 얻어온다.

     

     

    출처

    https://velog.io/@max9106/OAuth3

     

    [OAuth + Spring Boot + JWT] 3. 스프링 시큐리티는 OAuth 로그인을 어떻게 처리할까? 스프링 시큐리티 구

    이전글\[OAuth + Spring Boot + JWT] 1. OAuth란? 프론트엔드와 백엔드의 역할\[OAuth + Spring Boot + JWT] 2. 스프링 시큐리티로 OAuth 구현해보기스프링 시큐리티는 OAuth 로그인 요청을 어떤식으로 처리할까?스프

    velog.io

     

    반응형

    댓글

Designed by Tistory.