@ControllerAdivce란
@ControllerAdvice는 Spring에서 전역적인 예외 처리 기능을 제공하는 어노테이션이다. 이를 통해 애플리케이션의 모든 컨트롤러에서 발생하는 예외를 전역적으로 처리할 수 있다.
Spring Security는?
Spring Security는 웹 애플리케이션의 보안을 관리하는 프레임워크로, 인증(Authentication)과 인가(Authorization)를 주로 담당한다.
Spring Security는 필터 체인(Filter Chain) 방식으로 동작하는 보안 시스템이다.
즉, 사용자 요청이 들어올 때마다 필터들이 요청을 차례대로 처리한다.

Spring Security는 필터로 구현되어 있기 때문에, 예외를 컨트롤러에서 직접 처리할 수 없다.
Filter는 컨트롤러보다 앞단에서 동작하기 때문에 Filter에서 발생한 예외는 해당 Filter Chain 내에서 처리되므로, @ControllerAdvice에서 처리하는것은 불가능하다.
Spring Security 예외를 @ControllerAdvice에서 처리 하려면?
그렇다면 모든 예외를 @ControllerAdvice를 통해 전역적으로 처리 하려면 어떻게 해야 할까?
기본적으로 AuthenticationEntryPoint는 인증 및 인가 관련 예외(AuthenticationException, AccessDeniedException)를 처리하지만, 커스텀 예외를 처리하려면 예외를 HandlerExceptionResolver로 전달하는 방식으로 처리할 수 있다.
JWTFilter
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
// 헤더에서 Authorization 에 담긴 토큰을 꺼냄
String token = extractToken(request);
// 토큰이 없을 경우
if (token == null) {
throw new BadRequestException(ErrorCode.NO_TOKEN);
}
// 토큰 검증
validateToken(token);
// 토큰 검증 완료 후 토큰에서 userId 추출
Long userId = jwtUtil.getUserId(token);
// 추출한 userId로 사용자 조회
Optional<UserDto> byUserId = userRepository.findByUserId(userId);
if (byUserId.isEmpty()) {
throw new BadRequestException(ErrorCode.USER_NOT_FOUND);
}
// 사용자 정보를 SecurityContext에 저장
setAuthentication(byUserId.get());
} catch (BadRequestException ex) {
request.setAttribute("exception", ex);
}
filterChain.doFilter(request, response);
}
BadRequestException이 발생하고, request.setAttribute("exception", ex)를 통해 HttpServletRequest에 예외가 저장된다.
AuthenticationEntryPoint
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final HandlerExceptionResolver resolver;
public JwtAuthenticationEntryPoint(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
this.resolver = resolver;
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) {
resolver.resolveException(request, response, null, (Exception)request.getAttribute("exception"));
}
}
JwtAuthenticationEntryPoint는 AuthenticationEntryPoint를 구현하고 있으며, 커스텀 예외를 처리하기 위해 HandlerExceptionResolver를 사용했다.
AuthenticationEntryPoint의 commence 메서드에서 request.getAttribute("exception")을 확인하여, 커스텀 예외가 설정되어 있다면, 예외는 HandlerExceptionResolver를 통해 처리되고, ControllerAdvice에서 처리할 수 있다.
// 예외 처리
http.
exceptionHandling(
handler -> handler.authenticationEntryPoint(entryPoint)
);
SecurityConfig 파일에 해당 설정도 추가해 준다.
결론
Spring Security에서 발생하는 예외를 @ControllerAdvice에서 처리하려면, 기본적으로는 SecurityFilterChain 내에서 처리되기 때문에 @ControllerAdvice로 직접 처리할 수 없다.
하지만, AuthenticationEntryPoint와 HandlerExceptionResolver를 활용하면 예외 처리를 할 수 있다.
이를 통해 Spring Security에서 예외가 발생하더라도 @ControllerAdvice에서 전역적으로 처리할 수 있다.
'Java , Spring > Spring' 카테고리의 다른 글
| [Spring Cloud] Spring Cloud Gateway (그리고 Zuul 와 Netty) (2) | 2025.01.21 |
|---|---|
| [Spring] JWT 검증 방법 (대칭키, 비대칭키) (1) | 2025.01.16 |
| [Spring] CS 스터디 - 3주차 Spring & Network (1) | 2024.08.11 |
| [Spring] 선착순 쿠폰 동시성 문제 해결하기 (메세지큐 적용) (0) | 2024.06.26 |
| [Spring] JAR, WAR (1) | 2024.05.23 |
댓글