-
Oauth2 + JWT카테고리 없음 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()을 호출하면된다.