인터셉터
스프링 인터셉터
사용자 인가 없이 URL 을 직접 호출해서 페이지에 접속하는 것을 막아주는 역할을 한다.
스프링 MVC 가 제공하는 기술로, 필터와 비슷하지만 필터보다 더 편리하고, 정교하다.
인터셉터 흐름
HTTP 요청 > WAS > 필터 > 서블릿 > 인터셉터 > 컨트롤러
스프링 인터셉터는 디스패처 서블릿이 호출된 뒤, 컨트롤러 호출 직전에 호출된다.
(스프링 MVC 가 제공하는 기술이기 때문에 스프링 MVC 시작점인 디스패처 서블릿 이후에 등장한다.)
인터셉터에서 요청을 검토하여 적절하지 않은 요청이면 컨트롤러를 호출하지 않는다.
인터셉터 체인
HTTP 요청 > WAS > 필터 > 서블릿 > 인터셉터1 > 인터셉터2 > 인터셉터3 > 컨트롤러
또한 인터셉터는 체인으로 구성되어 중간에 인터셉터를 추가할 수 있다.
인터셉터 인터페이스
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {}
default void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, @Nullable ModelAndView modelAndView) throws Exception {}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, @Nullable Exception ex) throws Exception {}
}
인터셉터는 preHandle
, postHandle
, pafterCompletion
과 같이 세분화되어 있으며,
handler
의 호출 정보, modelAndView
의 반환 정보도 받을 수 있다.
인터셉터 인터페이스를 구현하고 등록하면, 스프링 컨테이너가 싱글톤 객체
로 생성하고, 관리한다.
preHandle
: 컨트롤러 호출 전에 호출, true 이면 다음으로 진행하고 false 면 더 이상 진행하지 않는다.
postHandle
: 컨트롤러 호출 후에 호출, 컨트롤러 예외 발생 시 호출 X
afterCompletion
: 뷰가 렌더링 된 이후 호출, 컨트롤러 예외 발생해도 항상 호출
preHandle ↗ ① preHandle ↗ |
||||||
클라이언트 | HTTP 요청 → → → → |
Dispatcher Servlet |
② handle(handler) → → → → → → ← ← ← ← ← ← ④ ModelAndView 반환 |
핸들러 어댑터 |
③ 핸들러 호출 → → → → |
핸들러 (컨트롤러) |
↓ ⑥ render(model) 호출 ↓ |
↘ ↘ ⑤ postHandle ↘ ↘ postHandle ↘ ↘ ⑦ afterCompletion afterCompletion |
|||||
HTML 응답 ← ← ← ← |
View |
요청 로그 인터셉터
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
public static final String LOG_ID = "logId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
String requestURI = request.getRequestURI();
String uuid = UUID.randomUUID().toString();
request.setAttribute(LOG_ID, uuid);
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
}
log.info("REQUEST [{}][{}][{}]", uuid, requestURI, handler);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle [{}]", modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
String requestURI = request.getRequestURI();
String logId = (String)request.getAttribute(LOG_ID);
log.info("RESPONSE [{}][{}]", logId, requestURI);
if (ex != null) {
log.error("afterCompletion error!!", ex);
}
}
}
UUID
: Http 요청을 구분하기 위해 요청당 임의의 uuid 생성
request.setAttribute(LOG_ID, uuid)
: 서블릿 필터의 경우 doFilter( ) 에서 요청이 들어와서 응답이 나갈 때까지 같은 실행 흐름에서 동작하지만
: 스프링 인터셉터의 경우 preHandle( ), postHandle( ), afterCompletion( ) 는 실행 시점이 다르기 때문에
: request 에 담아 한 요청에 같은 uuid 를 사용할 수 있다.
return true
: true 면 정상 호출로, 다음 인터셉터나 컨트롤러가 호출된다.
Object handler
: 스프링을 사용하여 @Controller, @RequestMapping 을 활용한 경우 > HandlerMethod
: @Controller 가 아닌 /resources/static 과 같은 정적 리소스가 호출되는 경우 > ResourceHttpRequestHandler
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/css/**", "/*.ico", "/error");
}
}
인터셉터를 등록해야 사용할 수 있다.
이때, WebMvcConfigurer 가 제공하는 addInterceptors()
를 사용하여 등록하면 된다.
registry.addInterceptor(new LogInterceptor())
: 등록할 인터셉터를 지정
order()
: 인터셉터의 순서 (낮을수록 먼저 동작)
addPathPatterns()
: 인터셉터를 적용할 URL 패턴 지정
excludePathPatterns()
: 인터셉터에서 제외할 패턴 지정
인증 체크 인터셉터
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("인증 체크 인터셉터 실행 {}", requestURI);
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null) {
log.info("미인증 사용자 요청");
response.sendRedirect("/login?redirectURL=" + requestURI);
return false;
}
return true;
}
}
response.sendRedirect("/login?redirectURL=" + requestURI);
: 미인증 사용자를 로그인 화면으로 리다이렉트
: 현재 요청 경로 requestURI 를 쿼리 파라미터로 함께 전달하여 로그인 성공 시 해당 경로로 이동할 수 있도록 함
return false;
: 다음 인터셉터나 컨트롤러가 호출되지 않는다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/css/**", "/*.ico", "/error");
registry.addInterceptor(new LoginCheckInterceptor())
.order(2)
.addPathPatterns("/**")
.excludePathPatterns("/", "/members/add", "/login", "/logout",
"/css/**", "/*.ico", "/error");
}
}
인터셉터를 적용하는 부분은 addPathPatterns
,
인터셉터를 적용하지 않을 부분은 excludePathPatterns
에 작성하면 된다.
registry.addInterceptor(new LoginCheckInterceptor())
: 등록할 인터셉터를 지정
order()
: 인터셉터의 순서 (낮을수록 먼저 동작)
addPathPatterns()
: 인터셉터를 적용할 URL 패턴 지정
excludePathPatterns()
: 인터셉터에서 제외할 패턴 지정
출처 | 스프링 MVC 2(김영한) - 인프런
'💠프로그래밍 언어 > Java' 카테고리의 다른 글
[Spring] 서블릿 예외 처리와 스프링 부트 예외 처리 (0) | 2025.04.04 |
---|---|
[Spring] 컨트롤러 공통 작업 자동화 (ArgumentResolver 의 활용) (0) | 2025.04.04 |
[Spring] 필터란 ? + 요청 로그 필터, 인증 체크 필터 예시 (0) | 2025.04.04 |
[Spring] 쿠키/세션으로 로그인 처리하기 (세션 저장소 만들기, HttpSession) (0) | 2025.04.03 |
[Spring] Bean Validation 사용하여 간편하게 검증 로직 추가하기 ! (0) | 2025.04.03 |