2024. 1. 15. 21:27ㆍ프로젝트/[EATceed] 몸무게 증량 어플
JwtAuthenticationFilter에서 토큰을 검증하는 과정에서 ExpiredJwtAuthenticationException, InvalidJwtAuthenticationException 등과 같이 AuthenticationException을 상속하여 만든 커스텀한 예외들이 터질 수 있다.
해당 예외들을 하나하나 전역적으로 예외 처리하려고 한다.
개념
먼저, Spring Security에는 AuthenticationException, AccessDeniedException 이 존재한다.
해당 예외들은 시큐리티 필터체인의 마지막에 속해있는 ExceptionTranslationFilter에서 처리할 수 있다.
ExceptionTranslationFilter는 필터체인에 속해져 있으므로, 예외는 일반적으로 @RestControllerAdvice + @ExceptionHander로 처리할 수 없다.
하지만, HandlerExceptionResolver를 사용하면 가능하다.
https://rasony.tistory.com/186
ExceptionTranslationFilter
ExceptionTranslationFilter에서는 AuthenticationException이 감지되면, 필터는 authenticationEntryPoint를 실행한다.
만약 AccessDeniedException이 감지되면, 필터는 사용자가 익명 사용자인지 여부를 결정하고, 익명 사용자인 경우 authenticationEntryPoint가 실행됩니다.
익명 사용자가 아닌 경우 AccessDeniedHandler 실행됩니다.
토큰을 검증할 때 발생할 수 있는 예외는 인증 예외이기 때문에 AuthenticationEntryPoint 인터페이스를 구현한 커스텀 JwtAuthenticationPoint를 만들어준다.
AuthenticationEntryPoint
public interface AuthenticationEntryPoint {
void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException;
}
@Component
public class JwtAuthenticationPoint implements AuthenticationEntryPoint {
private final HandlerExceptionResolver resolver;
public JwtAuthenticationPoint(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
this.resolver = resolver;
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException {
resolver.resolveException(request, response, null, authException);
}
}
해당 JwtAuthenticationPoint 클래스는 handlerExceptionResolver를 주입받는다.
HandlerExceptionResolver는 JwtAuthenticationFilter에서 발생한 예외를 DispatcherServlet으로부터 전달 받아 처리한다.
HandlerExceptionResolver에는 ExceptionHandlerExceptionResolver 구현체가 있는 데, 해당 클래스에서 @ExceptionHandler에 명시된 예외를 처리할 수 있다.
최종적으로, 전역 핸들러에서 필터에서 발생한 예외를 핸들링할 수 있다.
RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
...
@ExceptionHandler(ExpiredJwtAuthenticationException.class)
protected ApiResponse<?> handleExpiredJwtAuthenticationException(ExpiredJwtAuthenticationException e) {
return ApiResponseGenerator.fail(e.getMessageCode().getCode(), e.getMessageCode().getValue(), HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(InvalidJwtAuthenticationException.class)
protected ApiResponse<?> handleExpiredJwtAuthenticationException(InvalidJwtAuthenticationException e) {
return ApiResponseGenerator.fail(e.getMessageCode().getCode(), e.getMessageCode().getValue(), HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(UnsupportedAuthenticationException.class)
protected ApiResponse<?> handleExpiredJwtAuthenticationException(UnsupportedAuthenticationException e) {
return ApiResponseGenerator.fail(e.getMessageCode().getCode(), e.getMessageCode().getValue(), HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(AuthenticationException.class)
protected ApiResponse<?> handleExpiredJwtAuthenticationException(AuthenticationException e) {
return ApiResponseGenerator.fail(e.getMessage(), HttpStatus.UNAUTHORIZED);
}
...
}
감사합니다!
'프로젝트 > [EATceed] 몸무게 증량 어플' 카테고리의 다른 글
헥사고날 아키텍처 회고 (1) (0) | 2024.02.12 |
---|---|
리버스 프록시(Reverse Proxy) 설정 (2) | 2024.01.22 |
[Spring Security] @AuthenticationPrincipal을 커스텀 해보자(Feat : ArgumentResolver) (0) | 2024.01.11 |
JPA 대소문자 구별 에러 해결 with MariaDB (0) | 2024.01.01 |
Foreign key constraint is incorrectly formed 에러 해결 (1) | 2023.12.31 |