Spring Boot

스프링 인터셉터

mintuchel 2023. 12. 29. 20:53

 

스프링 인터셉터도 서블릿 필터, AOP와 동일하게 공통 관심 사항을 해결할 수 있는 기능임.

 

인터셉터는 그림에서 볼 수 있듯이 스프링 영역(Spring Context) 안에서 실행됨.

 

특정 Controller가 실행되기 전이나 실행된 후 추가적인 작업을 할 수 있도록 함.

 

서블릿 필터가 서블릿이 제공하는 기술이라면,

스프링 인터셉터는 스프링 MVC가 제공하는 기술이다.

 

둘 다 공통관심사항을 처리하지만, 적용되는 순서와 범위, 사용방법이 다름.

 

preHandle
1. 세션 체크: 세션에서 로그인 여부를 확인하고 로그인되지 않았으면 리다이렉트.
2. API Rate Limit (속도 제한): 사용자의 API 호출 횟수를 제한
3. 특정 URL 접근 제한: 관리자 페이지 접근 권한 체크

postHandle
4. 공통 응답 데이터 추가: 응답 헤더에 공통 데이터를 추가

 


[Interceptor를 사용하는 이유]

 

로그인 체크 또는 권한 체크를 각 Controller 에서 할 경우에는 다음과 같은 문제점이 생김.

 

1) 메모리 낭비, 서버의 부하가 늘어난다.

적용해야할 핸들러만 수만큼 세션체크 코드를 작성함으로써 반복되는 코드들이 매우 많아지기 때문이다.

 

2) 코드 누락에 대한 걱정이다. 

사람이 작성을 하는것이기 때문에 누락과 같은 실수가 발생할수 밖에없다.

 만약 회원정보에 접근하는 핸들러가 세션체크가 누락되어서 관리자 인지 확인을 안한다면, 자격이 없는 사용자가

 접근할수 있게되어 보안적으로 큰 문제를 가지게 된다.

 

이러한 문제점을 줄이기 위한 수단으로, 개발자는 인터셉터를 사용할수 있다.

인터셉터를 사용하게 되면 개발자는 핸들러 수 만큼 작성했던 세션 체크 코드를 인터셉터 클래스에 한번만 작성하면된다. 이로 인해 코드의 량이 현저히 줄기 대문에 메모리 낭비를 줄일수 있다.

그리고 인터셉터 적용의 유무 기준이 되는 url을 servlet-context.xml에 설정해주게 되면 스프링에서 일괄적으로

해당 url 경로의 핸들러에 인터셉터를 적용해주기 때문에 누락에 대한 위험이 상당히 줄게된다.


[로그인 체크(세션 처리)를 인터셉터에서 하는 이유?]

 

세션(HttpSession)은 스프링 컨텍스트 내부에서 관리된다!

 

세션은 HttpSession을 이용해 스프링이 관리하는 방식이므로, Spring MVC 레이어에서 처리하는 것이 자연스럽다.

따라서 Spring Context 밖에 있는 서블릿 필터에서 처리하는 것보다, 스프링 내부에서 동작하는 인터셉터에서 처리하는게 적절하다.

 


HTTP 요청 > WAS > 서블릿 필터 > 디스패처 서블릿 > 스프링 인터셉터 > 컨트롤러

 

스프링 인터셉터는 디스패처 서블릿이 URI에 맞는 컨트롤러를 호출하기 직전에 작동한다.

스프링 인터셉터는 결국 스프링 MVC가 제공하는 기능이기 때문에 디스패처 서블릿 이후에 등장하게 된다.

 


[HandlerInterceptor 인터페이스]

 

interface HandlerInterceptor를 구현하고 등록하면 Servlet Container가 커스텀하여 등록한 필터를 싱글톤 객체로 생성하고 관리함.

public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return true;
    }

    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 {
    }
}

 

1. preHandle()

컨트롤러 호출 전에 호출된다.

 

2. postHandle()

컨트롤러 호출 후에 호출된다.

 

3. afterCompletion()

뷰가 렌더링 된 이후에 호출된다.

afterCompletion은 항상 호출된다!!

 

컨트롤러에서 예외 발생 시에는??

예외가 발생하면 postHandle()은 호출되지 않는다.

하지만 afterCompletion()은 항상 호출되므로 예외가 발생하더라도 호출이 된다!

 

인터셉터는 스프링 MVC 구조에 특화된 필터 기능을 제공한다고 이해하면 된다. 스프링 MVC를 사용하고, 특별히 필터

를 꼭 사용해야 하는 상황이 아니라면 인터셉터를 사용하는 것이 더 편리하다.

 


[WebConfig를 통한 커스텀 인터셉터 등록]

 

WebMvcConfigurer가 제공하는 addInterceptor()를 사용해서 인터셉터를 등록할 수 있다.

 

@Configuration
public class WebConfig implements WebMvcConfigurer{
	@Override
    public void addInterceptors(InterceptorRegistry registry) {
    	registry.addInterceptor(new LogInterceptor())
        	.order(1)
            .addPathPatterns("/**")
            .excludePathPatterns("/css/**", "/*.ico", "/error")
    }
    
    //...
}

 

1. registry.addInterceptor( )

인터셉터를 등록한다

 

2. order(1)

인터셉터의 호출 순서 지정. 낮을수록 먼저 호출됨.

 

3. addUrlPatterns()

인터셉터를 적용할 URL 패턴을 지정한다.

 

4. excludePathPatterns()인터셉터에서 제외할 패턴을 지정한다

 

스프링이 제공하는 URL 경로는 서블릿 기술이 제공하는 URL 경로와 완전히 다르다. 더욱 자세하고, 세밀하게 설정할

수 있다.

 

https://supawer0728.github.io/2018/04/04/spring-filter-interceptor/

 

(Spring)Filter와 Interceptor의 차이

서론Spring을 익힌지 얼마 되지 않았을 때, 회원 인증 로직을 구현할 일이 생겼었다. 그 인증을 구현하기 위해 Filter와 Interceptor를 조사했었다. 하지만 Filter와 Interceptor를 어떤 경우에 써야 좋은지

supawer0728.github.io