스프링에서 리다이렉트했는데 자꾸 로그인 페이지로 넘어갈 때

 

문제

OAuth2SuccessHandler에서 프론트에 토큰  값을 전달하기 위해 redirect를 설정했더니 다시 로그인 페이지로 리다이렉트되는 현상

 

해결

현재 OAuth2SuccessHandler 설정

@RequiredArgsConstructor
@Component
public class OAuth2SuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    private final JwtProvider jwtProvider;

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException {
        super.clearAuthenticationAttributes(request);

        CustomOAuth2User auth2User = (CustomOAuth2User) authentication.getPrincipal();
        Long userId = auth2User.getUserId();
        String role = auth2User.getRole();

        String generatedToken = jwtProvider.generateToken(userId, role, ACCESS_TOKEN_DURATION);
        response.setHeader(HEADER_AUTHORIZATION, generatedToken);
        response.sendRedirect("/login/success");
    }

}

프론트에서는 응답에 포함된 토큰값을 쿠키에 저장하여 인증을 유지한다.

때문에 인증에 성공하면 정해진 경로로 우회한다. 

 

그리고 문제의 현상인 로그인페이지로 넘어가게 되는데,

이 현상에는 감춰져 있는 요청 처리가 있다.

먼저, 웹서버 없이 로컬에서 구현하기 때문에 위 엔드포인트를 처리할 수 있는 컨트롤러가 정의되어 있지 않다.

따라서 스프링은 자연스레 /error 페이지로 우회시킨다.

문제는 이 /error 경로를 spring security에서 authenticated로 보호되고 있기 때문에 사용자가 인증되었는지 확인하고

안되어있다면 다시 로그인 페이지로 넘어가는 것이다.

 

그렇다면 해결방안은 /error를 인증없이 접근할 수 있도록 하는 것이다.

물론, 웹서버를 실행시켜 엔드포인트 LB를 진행해도 되지만 구현할 때마다 키는 것은 불편하므로 이렇게 해결하는 편이 좋겠다 생각했다.

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
public class OAuth2LoginConfig {

    private final CustomOAuth2UserService oAuth2UserService;
    private final OAuth2SuccessHandler oAuth2SuccessHandler;
    private final JwtAuthenticationFilter jwtAuthenticationFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.oauth2Login(oauth2Login ->
                oauth2Login
                        .successHandler(oAuth2SuccessHandler)
                        .userInfoEndpoint(userInfoEndpointConfig ->
                                userInfoEndpointConfig.userService(oAuth2UserService)));

        http.sessionManagement((sessionManagement) ->
                sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        http.addFilterAfter(jwtAuthenticationFilter, OAuth2LoginAuthenticationFilter.class);

        // 로컬 환경에서는 서버 사이드로 구현하기 때문에 일부 엔드포인트 개방
        http.authorizeHttpRequests(a ->
                a.requestMatchers("/login/success").permitAll());

        http.authorizeHttpRequests(a ->
                a.requestMatchers("/error").permitAll()
                        .requestMatchers("/api/login").permitAll()
                        .requestMatchers("/login/success").permitAll()
                        .anyRequest().authenticated());

        return http.build();
    }
}