Back-end/Spring-Security

SpringSecurity를 사용할 때 일관적인 Exception 처리를 위해

prden 2023. 6. 27. 21:15

1. Spring Security Filter chain의 구조

https://jhkimmm.tistory.com/29

따라서 @Controller나 @Service에서 GlobalCustomException처리하면 (@ControllerAdvice, @ExceptionHandler) 해당 메소드로 넘어가지만, Filter에서 똑같이 Exception 터트려도 GlobalCustomException로 넘어가지 않는다. 

 

해결방법은 Filter영역에서 Exception 처리는 아래와 같이.

@Component
// 유효한 자격증명을 제공하지 않고 접근하려 할 때 401Unauthorized 에러를 리턴
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException authException) throws IOException {

        // 필터에서 터지는 에러는 이 형식으로 통일
        ObjectMapper objectMapper = new ObjectMapper();
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        objectMapper.writeValue(response.getWriter(), new ErrorResponse(ErrorCode.HANDLE_UNAUTHORIZED));
    }
}
public class JwtFilter extends OncePerRequestFilter {


// 토큰 유효성 검사 ATOrRT(AccessToken, RefreshToken)
public boolean validateToken(String token, String ATOrRT, HttpServletResponse servletResponse) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();

    try{
        Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
        return true;
    } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
        logger.info("잘못된 JWT 서명입니다.");
    } catch (ExpiredJwtException e) {
        logger.info("만료된 JWT 토큰입니다.");
        if(Objects.equals(ATOrRT, "AT")){
            servletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            servletResponse.setCharacterEncoding("UTF-8");
            objectMapper.writeValue(servletResponse.getWriter(), new ErrorResponse(ErrorCode.EXPIRED_ACCESS_TOKEN));
            //throw new ExpiredAccessToken(ErrorCode.EXPIRED_ACCESS_TOKEN.getMessage()); //
            // 필터 영역이라서 예외 던저도 GlobalCustomException 처리 안됨.
        }else {
            servletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            servletResponse.setCharacterEncoding("UTF-8");
            objectMapper.writeValue(servletResponse.getWriter(), new ErrorResponse(ErrorCode.EXPIRED_REFRESH_TOKEN));
            // throw new ExpiredRefreshToken(ErrorCode.EXPIRED_REFRESH_TOKEN.getMessage());
            // 필터 영역이라서 예외 던저도 GlobalCustomException 처리 안됨.
        }
    } catch (UnsupportedJwtException e) {
        logger.info("지원되지 않는 JWT 토큰입니다.");
    } catch (IllegalArgumentException e) {
        logger.info("JWT 토큰이 잘못되었습니다.");
    }
    return false;
}

 

참고: https://jhkimmm.tistory.com/29

 

[Spring Security] Filter 에서 발생한 예외 핸들링하기

Spring Security에서 JWT를 사용한 인증에서 발생할 수 있는 ExpiredJwtException, JwtException, IllegalArgumentException과 같이 Filter에서 발생하는 Exception을 핸들링하는 방식에 대해 알아보겠습니다. @ControllerAdvice

jhkimmm.tistory.com

https://velog.io/@coastby/SpringSecurity-filter-%EB%82%B4%EC%97%90%EC%84%9C-%EB%B0%9C%EC%83%9D%ED%95%9C-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0

 

[SpringSecurity] filter 내에서 발생한 예외 처리하기

REST 예외를 처리하기 위해 일반적으로 Spring MVC에서 @ControllerAdvice 및 @ExceptionHandler를 사용하지만 이러한 핸들러는 요청이 DispatcherServlet에 의해 처리되는 경우 작동한다. 그러나 보안 관련 예외는

velog.io