카테고리 없음

Oauth2 + JWT

now0204 2024. 2. 11. 01:43

 

OAuth2 동작원리

출처: 유튜브 (개발자 유미)

 

OAuth2 변수 설정 

#registration
spring.security.oauth2.client.registration.naver.client-name=naver
spring.security.oauth2.client.registration.naver.client-id=발급아이디
spring.security.oauth2.client.registration.naver.client-secret=발급비밀번호
spring.security.oauth2.client.registration.naver.redirect-uri=http://localhost:8080/login/oauth2/code/naver
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.scope=name,email

#provider
spring.security.oauth2.client.provider.naver.authorization-uri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.token-uri=https://nid.naver.com/oauth2.0/token
spring.security.oauth2.client.provider.naver.user-info-uri=https://openapi.naver.com/v1/nid/me
spring.security.oauth2.client.provider.naver.user-name-attribute=response

 

-> redirect-uri : 로그인 성공 후 로그인 완료시 -> From 인증서버 to 어플리케이션 서버 

   보통 /login/oauth2/code/서비스명으로 고정 (커스텀 설정 가능) 

 

@Service
@Slf4j
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        //기본 OAuth2UserService 객체 생성 (기본으로 등록된 Service와 Custom을 동시에 사용할 것이다)
        OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService = new DefaultOAuth2UserService();

        //OAuth2USerService를 사용하여 OAuth2User정보를 가져오기
        OAuth2User oAuth2User = oAuth2UserService.loadUser(userRequest);
        log.info("oauth2User  = {}",oAuth2User);

        

        //클라이언트 등록아이디인 Naver,google,kakao 같은 정보를 가져움
        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        OAuth2Response oAuth2Response = null;

        return null;
    }
}

 

-> OAuth 인증을 진행 -> 외부 인증서버에서 인증에 성공하면,

   OAuth2UserRequest 객체에 제공자에 대한 정보, 엑세스 토큰 등과 같은 정보를 넣어서

   CustomOAuth2UserService로 넘어옴! 

 

	private final ClientRegistration clientRegistration;

	private final OAuth2AccessToken accessToken;

	private final Map<String, Object> additionalParameters;
User Attributes: [{resultcode=00, message=success, response={id=ZvmRu4IZEdjDsvi-GBdpqim75HhBUQPmsdE-8sORKRs, email=이메일, name=사용자명}}]

 

 

 

- 처음에 변수에 설정한 

 /oauth2/authorization/kakao로 요청

-> OAuth2AuthorizationRequestRedirectFilter의  doFilter발동

-> DefaultOAuth2AuthorizationRequestResolver의 resolve메서드 내부호출 -> 요청이 필요로 하는 페이지로 redirect시켜줌 (redirect로 설정한 페이지) 

   -> resolve메서드 내부에서 resolveRegistationId를 request에서 뽑고 null인지 아닌지 확인

    -> resolveRegistrationId는 요청 uri가 해당 pattern과 일치하면 uri에서 REGISTRATION_ID_URI_VARIABLE_NAME를 꺼내서 값을 반환

autorizationRequestBaseUri + / + {registrationId} (매칭되는 값)

 

-> OAuth2ClientConfigurer파일에 BaseUri가 등록되어있음 (/oauth2/authorization)

->resolve메서드는 redirect-uri를 만들고 가공  (application.yml에 registraionId(naver,kakao)를 가져옴

 

1. 사용자가 /oauth2/authorization/kakao로 요청

2. ReqeustResolver가  uri패턴 검사 (/oauth2/authorization/{registrationId} 패턴이 맞으면 registraionId변수에 바인딩된 변수를 가져옴 

3. 변수값을 바탕으로 ClientRegistraion조회

4. 해당 값으로 redirect-uri가공

5. 사용자에게 가공된 redicrect-rui로 해당 페이지 redirect함  

//

요청보내면, 여기까지 오는 흐름 인 것 같다
https://nid.naver.com/oauth2.0/authorize

 

-> 해당 페이지에서 이메일 비밀번호 입력후 로그인 완료 

-> 우리 애플리케이션 측에 redirect-uri로 인증코드, access토큰 발급 해줄 것이다.

 

1. OAuth2LoginAuthenticationFilter에 attemptAuthentication 메서드 호출 -> Provider Manager의 authenticate메서드 호출

2. OAuth2LoginAuthenticationProvider의 authenticate 한번 더 호출 -> 인가받은 코드로  Access Token API 호출

3. Access Token을 받아오면, OAuth2User에 LoadUser메서드 호출 -> userService에 loadUser 메서드 호출되고 ->

Oaut2UserDetail을 반환 (UserService내부에서 load.user를 통해 Access Token의 사용자 정보 읽음)

-> 일단 여기까지 흐름이 오면, 소셜 로그인은 완료한 것이다. 따라서 해당 웹어플리케이션에 user가 있는지 없는지 검사하고 -> 새로운 회원가입 혹은 AccessToken을 발급해주자

 

 

 

*Session create policy stateless

->한 요청의 응답이 나갈때 까지만, 유지된다. 따라서 oauth2로 로그인이 완료될 때까진 유지됨

-> oauth2로 로그인이 완료되면,

 Authentication auth = getAuthentication(Oauth2User);
 SecurityContextHolder.getContext().setAuthentication(auth);

 

-> 위와 같은 메서드를 따라 SecurityContext에 Oauth2User를 한번 저장함 

-> Security Context란 스프링 시큐리티 내부에 세션저장소와 비슷한 개념으로, 여기에 저장할 수 있는 값은 

-> Authentication 객체 뿐이다. 

 -> 값을 꺼낼 때는 어노테이션을 사용하던, SecurityContextHolder.getContext.getAuthentication()을 호출하면된다.