JWT 인증 예외가 GlobalExceptionHandler로 안 잡히는 이유

Xylitol311·2026년 1월 31일

Back-end

목록 보기
13/14
post-thumbnail

JWT 기반 인증을 구현하고 GlobalExceptionHandler도 잘 만들어뒀다. 컨트롤러에서 발생하는 예외는 모두 깔끔하게 처리되고 있었다. 그런데 만료된 JWT 토큰으로 요청을 보내면 GlobalExceptionHandler를 거치지 않고 그냥 500 에러가 터졌다.

분명 @RestControllerAdvice로 모든 예외를 처리하게 해뒀는데 왜 안 잡히지? 로그를 찍어봐도 GlobalExceptionHandler는 아예 호출조차 안 된다. 바보 같이 JWT 검증은 필터에서 일어나고, 필터 예외는 컨트롤러까지 도달하지 않는다는 사실을 까먹고 있었다.

결국 ExceptionHandlerFilter를 따로 만들어서 해결했고, 또 까먹고 바보 같은 짓을 반복하지 않기 위해 정리를 좀 해두려고 한다.

핵심 개념

Spring Security를 사용하는 애플리케이션에서 예외 처리는 두 계층으로 나뉜다:

  • ExceptionHandlerFilter: 필터 체인 단계의 예외 처리
  • GlobalExceptionHandler: 컨트롤러 단계의 예외 처리

이 둘은 동작하는 위치가 다르기 때문에 처리할 수 있는 예외의 범위도 다르다.

요청 처리 흐름

주요 차이점

1. 동작 위치 (가장 중요)

ExceptionHandlerFilter

  • Spring Security Filter Chain에서 동작
  • OncePerRequestFilter 상속
  • DispatcherServlet 도달 이전 예외 처리

GlobalExceptionHandler

  • Spring MVC 레이어에서 동작
  • @RestControllerAdvice 사용
  • Controller에서 발생한 예외 처리

2. 예외 처리 방식

ExceptionHandlerFilter

@Override
protected void doFilterInternal(HttpServletRequest request, 
                                HttpServletResponse response, 
                                FilterChain filterChain) {
    try {
        filterChain.doFilter(request, response);
    } catch (InvalidTokenException e) {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        objectMapper.writeValue(response.getWriter(), errorResponse);
    }
}

GlobalExceptionHandler

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ServiceException.class)
    public ResponseEntity<ErrorResponse> handleServiceException(ServiceException e) {
        return ResponseEntity.status(e.getErrorCode().getStatus())
                           .body(errorResponse);
    }
}

실무 활용

ExceptionHandlerFilter 사용 시나리오

  • JWT 토큰 만료/위조
  • 인증 헤더 누락
  • Spring Security 필터 체인에서 발생하는 모든 예외

GlobalExceptionHandler 사용 시나리오

  • 존재하지 않는 리소스 조회 (404)
  • 중복 데이터 생성 시도 (409)
  • 비즈니스 검증 실패 (400)

주의사항

CORS 처리

ExceptionHandlerFilter에서는 CORS 헤더를 명시적으로 추가해야 한다. 필터 단계에서는 Spring의 CORS 설정이 적용되지 않기 때문이다.

필터 순서

ExceptionHandlerFilter는 반드시 다른 필터들보다 앞에 위치해야 한다.

http.addFilterBefore(exceptionHandlerFilter, JwtAuthenticationFilter.class);

핵심 요약

  1. 필터 예외는 @RestControllerAdvice로 처리 불가능
  2. ExceptionHandlerFilter: 필터 체인 예외 → HttpServletResponse 직접 작성
  3. GlobalExceptionHandler: 컨트롤러 예외 → ResponseEntity 반환
  4. 역할 분리: 보안 계층 vs 애플리케이션 계층
  5. CORS와 필터 순서에 주의
profile
문제에 도전하고 성장하는 백엔드 개발자입니다.

0개의 댓글