spring
Try Using Oauth2 in Spring Security 6x

spring security 6.x 버전에서 oauth2 사용해보기

대략적인 흐름도

카카오톡의 oauth2 흐름 예시

picture 0
참고 : 카카오 로그인 가이드 (opens in a new tab)

직접 작성

picture 0

1. OAuth2AuthorizationRequestRedirectFilter 를 통한 필터링

http://localhost:8080/oauth2/authorization/google 로 들어온 요청을 캐치해서

config 에 정의된 redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" 로 리다이렉트 시킨다, response.sendRedirect(redirectUrl); 이렇게 리스폰스 객체로 바로 리다이렉트 보내버림

2. OAuth2LoginAuthenticationFilter 를 통한 인증 처리

Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) 함수에서 인증 처리가 진행됨

  • 사용자 요청을 OAuth2AuthorizationRequest authorizationRequest 로 만듬
  • authorizationRequest 를 이용해 OAuth2LoginAuthenticationToken authenticationRequest 를 만듬
		OAuth2LoginAuthenticationToken authenticationResult = (OAuth2LoginAuthenticationToken) this
			.getAuthenticationManager()
			.authenticate(authenticationRequest);
  • 위와 같이 getAuthenticationManager 를 이용하여 인증을 진행하여 OAuth2LoginAuthenticationToken authenticationResult 를 만들어냄

인증 완료되면 기본값으로 "/" path 로 리다이렉트 함, 그런데 서버가 localhost:8080 으로 동작 중이고, 웹 페이지가 localhost:3000 에서 동작중이면, localhost:8080/ 로 리다이렉트되기 때문에 / 요청이 왔을 경우 로그인 요청이 왔던 Referer 주소로 리다이렉트 시켜줘야함

이는 별도의 복잡한 코딩없이

successHandler.setUseReferer(true); 만 해주면 요청했던 주소로 리다이렉트 됨

@Configuration
@EnableWebSecurity
public class SecurityConfig {
 
    private AuthenticationSuccessHandler getSuccessHandler() {
        var successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        successHandler.setUseReferer(true);
        return successHandler;
    }
 
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 
        http
                .authorizeHttpRequests(authorizeRequests -> authorizeRequests
                        .anyRequest().authenticated())
                .oauth2Login(httpSecurity -> httpSecurity.successHandler(getSuccessHandler()));
 
        return http.build();
    }
}

코드를 직접 타고가면서 확인한 로직,

AbstractAuthenticationTargetUrlRequestHandler 클래스의 아래 함수를 보면 알 수 있음

	/**
	 * Builds the target URL according to the logic defined in the main class Javadoc.
	 */
	protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
		if (isAlwaysUseDefaultTargetUrl()) {
			return this.defaultTargetUrl;
		}
		String targetUrlParameterValue = getTargetUrlParameterValue(request);
		if (StringUtils.hasText(targetUrlParameterValue)) {
			trace("Using url %s from request parameter %s", targetUrlParameterValue, this.targetUrlParameter);
			return targetUrlParameterValue;
		}
		if (this.useReferer) {
			trace("Using url %s from Referer header", request.getHeader("Referer"));
			return request.getHeader("Referer");
		}
		return this.defaultTargetUrl;
	}