이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- HandlerInterceptor의
preHandle,postHandle,afterCompletion은 각각 언제 실행되는가?- HandlerMethod 정보가 필요한 공통 처리는 왜 Interceptor가 적합한가?
- Interceptor가 보안, 응답 body 변경, 예외 처리의 주력 도구가 되기 어려운 이유는 무엇인가?
개요
HandlerInterceptor는 Spring MVC 내부의 확장 지점이다. DispatcherServlet이 HandlerMapping으로 실행할 Handler를 찾은 뒤, HandlerAdapter가 Controller를 호출하기 전후에 Interceptor가 개입한다.
이 위치 덕분에 Interceptor는 Servlet Filter보다 MVC 정보를 더 많이 안다. 특히 HandlerMethod를 통해 Controller 클래스, 메서드, 애너테이션을 볼 수 있다. 반대로 Security Filter보다 늦게 실행되므로 인증/인가의 주력 도구로 쓰기에는 적합하지 않다. Spring 공식 문서도 path matching 불일치 가능성 때문에 보안 계층은 Spring Security나 Servlet FilterChain에 통합된 방식을 권장한다.
실행 메서드
preHandle은 Controller 실행 전에 호출된다. false를 반환하면 이후 handler 실행이 중단된다.
postHandle은 Controller가 실행된 뒤 View가 렌더링되기 전에 호출된다. REST API에서 @ResponseBody가 message converter로 처리되는 흐름에서는 기대와 다르게 느껴질 수 있다.
afterCompletion은 요청 처리가 완료된 뒤 호출된다. 예외가 발생했는지 확인할 수 있고, cleanup이나 최종 로그에 적합하다.
public class AdminAuditInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod method && method.hasMethodAnnotation(AdminAudit.class)) {
log.info("admin action handler={}", method.getMethod().getName());
}
return true;
}
}이 예제는 HandlerMethod 애너테이션을 읽으므로 Interceptor가 자연스럽다.
등록
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AdminAuditInterceptor())
.addPathPatterns("/admin/**");
}
}Interceptor는 MVC 설정으로 등록한다. path pattern으로 적용 범위를 좁힐 수 있다. 다만 path pattern은 Security matcher와 별개이므로 같은 보안 의미로 중복 관리하지 않도록 주의한다. 여러 HandlerMapping이 있는 환경에서 공통 Interceptor를 재사용해야 한다면 MappedInterceptor Bean 방식도 검토할 수 있다.
한계
Interceptor는 DispatcherServlet 이후에 실행된다. 그래서 Security FilterChain에서 차단된 요청은 Interceptor에 도달하지 않는다. 인증/인가의 표준 인프라, CSRF, session management, SecurityContext 처리와도 직접 연결되지 않는다.
응답 body 변경도 Interceptor의 주 역할이 아니다. Controller 반환값이 message converter를 거쳐 body가 되는 흐름을 바꾸려면 ResponseBodyAdvice가 더 정확하다. 예외 공통 처리는 @ControllerAdvice가 더 자연스럽다.
실전 팁
- HandlerMethod 애너테이션 기반 정책에는 Interceptor를 고려한다.
- 인증/인가를 Interceptor로 직접 만들기보다 Spring Security를 먼저 사용한다.
- Interceptor path pattern을 보안 규칙의 유일한 기준으로 삼지 않는다.
- 응답 body wrapping은 Interceptor보다
ResponseBodyAdvice를 검토한다. - 요청 완료 로그가 필요하면
afterCompletion을 활용한다. - Interceptor path pattern과 Security matcher가 어긋나지 않게 문서화한다.
위험 신호!
- Interceptor에서 JWT를 검증하고 SecurityContext를 수동으로 구성한다.
- Interceptor에서 JSON 응답 body 문자열을 직접 바꾼다.
preHandlefalse 반환 후 응답 status와 body를 명확히 쓰지 않는다.- Security 규칙과 Interceptor path pattern이 서로 다른 보호 범위를 만든다.
- 여러 HandlerMapping이 있는데 Interceptor 등록 방식 때문에 일부 handler에만 적용된다.
- Interceptor에 비즈니스 유스케이스 로직이 들어간다.
확인 질문
확인 질문
preHandle이 false를 반환하면 어떻게 되는가?
- Controller 실행을 포함한 이후 MVC 처리가 중단된다.
- Interceptor가 Filter보다 Handler 정보에 강한 이유는 무엇인가?
- HandlerMapping 이후에 실행되어 HandlerMethod 정보를 받을 수 있기 때문이다.
- 응답 body 공통 변환에는 무엇을 검토하는 것이 좋은가?
ResponseBodyAdvice를 검토하는 것이 좋다.