말 그대로 요청이 실행되기 전에 가로채서 로직을 수행하는 역할을 한다. 스프링에서는 컨트롤러에 있는 요청을 실행하기 전, 컨트롤러의 로직을 실행한 이후에 특정 로직을 수행할 때 사용한다. 인터셉터를 활용하여 모든 컨트롤러 API 내의 중복적인 코드를 줄일 수 있다. 컨트롤러에서 사용되는 공통 로직을 먼저(혹은 나중에) 수행하므로 주로 사용자 인증 정보 확인 을 할 경우에 사용한다.

HandlerInterceptorAdapter

인터셉터 객체를 생성할 경우 HandlerInterceptorAdapter 를 상속받아야 한다. HandlerInterceptorAdapter 에서 제공하는 메서드는 다음과 같이 세 가지가 있다.

public class Intercepter extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // TODO Auto-generated method stub
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub
        super.afterCompletion(request, response, handler, ex);
    }
}

https://to-dy.tistory.com/21

Interceptor 동작 순서

Interceptor 활용

예를 들어, 사용자 인증 정보를 토큰으로 관리한다 할 때 토큰이 유효한지 확인하는 과정에서 활용할 수 있다. 다음 예제는 우아한테크코스 장바구니 미션 중 로그인 인터셉터 객체를 가져온 것이다. 컨트롤러 로직이 수행되기 전, 사용자를 식별해야 하는 로직을 요청할 경우(클라이언트로부터 토큰을 받아온다면) 받아온 토큰이 유효한지 확인하는 역할을 한다.

src/main/java/woowacourse/auth/ui/LoginInterceptor.java

package woowacourse.auth.ui;

import org.springframework.web.cors.CorsUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import woowacourse.auth.application.AuthService;
import woowacourse.auth.support.AuthorizationExtractor;
import woowacourse.shoppingcart.exception.token.InvalidTokenException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor extends HandlerInterceptorAdapter {

    private final AuthService authService;

    public LoginInterceptor(final AuthService authService) {
        this.authService = authService;
    }

    @Override
    public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception {
        if (CorsUtils.isPreFlightRequest(request)) {
            return true;
        }
        String accessToken = AuthorizationExtractor.extract(request); // 토큰 추출
        validateToken(accessToken); // 토큰 확인
        return true; // 유효한 토큰일 경우 true 반환하여 컨트롤러 수행
    }

    private void validateToken(final String accessToken) {
        if (accessToken == null || !authService.validateToken(accessToken)) {
            throw new InvalidTokenException("로그인을 해주세요.");
        }
    }
}

인증이 필요한 모든 로직 전에 토큰 정보를 확인해야 하므로 preHandle 메서드를 오버라이딩하였다. 요청 객체로부터 token 을 추출하고 추출한 토큰이 유효한지 확인한다. 유효하지 않을 경우 예외가 발생되며, 유효할 경우 true 를 반환하여 컨트롤러 로직이 수행되도록 한다.

src/main/java/woowacourse/auth/config/AuthenticationPrincipalConfig.java

package woowacourse.auth.config;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import woowacourse.auth.ui.AuthenticationPrincipalArgumentResolver;
import woowacourse.auth.application.AuthService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import woowacourse.auth.ui.LoginInterceptor;

import java.util.List;

@Configuration
public class AuthenticationPrincipalConfig implements WebMvcConfigurer {
    private final AuthService authService;

    public AuthenticationPrincipalConfig(AuthService authService) {
        this.authService = authService;
    }

		// 인터셉터 추가
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor(authService))
								.addPathPatterns("/auth/**"); // 해당 URL 로 들어오는 요청은 LoginInterceptor 실행
    }

    @Override
    public void addArgumentResolvers(List argumentResolvers) {
        argumentResolvers.add(createAuthenticationPrincipalArgumentResolver());
    }

    @Bean
    public AuthenticationPrincipalArgumentResolver createAuthenticationPrincipalArgumentResolver() {
        return new AuthenticationPrincipalArgumentResolver(authService);
    }
}

WebMvcConfigurer 를 구현한 config 객체를 생성하여 Interceptor 를 등록한다. WebMvcConfigurer 는 Spring MVC 에서 필요한 설정들을 관리하는 인터페이스이다. addInterceptors 를 이용하여 앞에서 생성한 LoginInterceptor 를 등록한다. 특정 URL 로 요청이 들어왔을 경우에만 인터셉터를 실행하기 위해 URL 도 설정한다. (사용자를 식별하지 않아도 요청할 수 있는 기능도 있음) excludePathPatterns 를 사용하면 특정 URL 을 제외할 수도 있다.