Spring Security JWTFilter에서 Exception 처리하기

2024. 7. 28. 16:36Spring

JWT 토큰 로그인을 구현하다가, JWT Filter에서 토큰 관련하여 잘못된 요청이 들어오면

CustomException을 던지는 방식으로 코드를 작성했는데 아무리해도 Exception 처리가 안되는 것 같았다.

 

찾아보니 Spring Security 에서는 기존에 사용하던 Custom Exception 을 처리하지 못한다고 한다.

 

그 이유는

Filter는 Dispatcher Servlet보다 앞단에 존재하고 Handler Interceptor는 뒷단에 존재하기 때문에

Filter에서 보낸 예외는 Exception Handler로 처리를 못한다.

 

-> 설정을 따로 해줘야 한다 !

 

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        http
                .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() {

                    @Override
                    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {

                        CorsConfiguration configuration = new CorsConfiguration();

                        configuration.setAllowedOrigins(Arrays.asList("http://localhost:5173", "http://localhost:3000"));
                        configuration.setAllowedMethods(Collections.singletonList("*"));
                        configuration.setAllowCredentials(true);
                        configuration.setAllowedHeaders(Collections.singletonList("*"));
                        configuration.setMaxAge(3600L);

                        configuration.setExposedHeaders(Collections.singletonList("Set-Cookie"));
                        configuration.setExposedHeaders(Collections.singletonList("access"));

                        return configuration;
                    }
                }));


   
        // 예외 처리 설정
        http.exceptionHandling(exceptionHandling -> exceptionHandling
                .authenticationEntryPoint(customAuthenticationEntryPoint)
                .accessDeniedHandler(customAccessDeniedHandler)
        );

 

SecurityConfig 파일에서 http.exceptionHandling 을 사용하여 exception을 handling 해주면 된다.

위와 같이 코드를 적어주고,

 

AuthenticationEntryPoint를 implement한 CustomAuthenticationEntryPoint 클래스를 작성해준다.

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        ApiResponse<Object> responseBody = ApiResponse.error(UNAUTHORIZED, "만료되었거나 잘못된 토큰입니다. 토큰을 확인해주세요.");
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getWriter().write(new ObjectMapper().writeValueAsString(responseBody));
    }
}

 

그리고 AccessDeniedHandler를 implement 한 CustomAccessDeniedHandler 클래스도 작성해준다.

@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        ApiResponse<Object> responseBody = ApiResponse.error(UNAUTHORIZED, "만료되었거나 잘못된 토큰입니다. 토큰을 확인해주세요.");
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.getWriter().write(new ObjectMapper().writeValueAsString(responseBody));
    }
}

 

 

참고 : 

https://velog.io/@jsang_log/Security-Filter-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0-JWT