(2) 로그인 처리2 - 인터셉터

CJY·2023년 4월 8일
0

스프링

목록 보기
11/14

인터셉터

스프링이 제공하는 인터셉터도 서블릿 필터와 같은 기능을 한다. 웹과 관련되 공통 관심 사항을 효과적으로 해결할 수 있다.

다른점은 필터는 서블릿이 제공하는 기술이고, 인터셉터는 스프링 MVC가 제공하는 기술이다. 적용되는 순서와 범위 그리고 사용방법에 있어 차이가 있다.

스프링 인터셉터 흐름

HTTP 요청 \rarr WAS \rarr 필터 \rarr 서블릿 \rarr 인터셉터 \rarr 컨트롤러

서블릿은 디스패처 서블릿을 가르킨다.
스프링 MVC의 시작점은 디스패처 서블릿이고 이 디스패처 서블릿을 지나 인터셉터가 적용된다.

따라서 디스패처 서블릿을 지났지만 스프링 인터셉터에서 적절하지 않은 요청이라 판단하면 컨트롤러까지 요청이 진행되지 않는다.

스프링 인터셉터 역시 체인 구조를 가진다.

HTTP 요청 \rarr WAS \rarr 필터 \rarr 서블릿 \rarr 인터셉터1 \rarr 인터셉터2 \rarr 컨트롤러

지금까지 살펴보면 필터와 그냥 순서차이만 나는거 아닌가? 이제 차이점을 천천히 알아보자.

스프링 인터셉터 인터페이스

스프링의 인터셉터 인터페이스는 HandlerInterceptor이다. 이 인터페이스를 구현하면 된다.

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

서블릿 필터는 doFilter()만 제공했지만 스프링 인터셉터는 3가지 함수를 제공한다. 이 3가지 함수를 제공하는 이유는 순서에 있다.

컨트롤러 호출 전 preHandle이, 호출 후에는 postHandle이, 요청이 완료되고 나서(View까지 보냄)는 afterCompletion이 기능을 한다.

파라미터를 보면 ServletRequest가 아니고 HttpServletRequest이다. 그리고 Object handler는 어떤 컨트롤러가 호출되는지에 대한 정보가 있다. 그리고 어떤 ModelAndView가 반환되는지에 대해도 알 수 있다. afterCompletion은 예외도 파라미터로 받는다.

만약 컨트롤러에서 예외가 발생한 경우 preHandle은 이미 컨트롤러 전에 호출됐으므로 상관이 없다. 그런데 postHandle은 예외가 발생한 경우 호출되지 않는다. 마지막으로 afterCompletion은 예외와 무관하게 항상 호출되는 함수이다.

Object handler

preHandle에서 받아오는 파라미터 중 Object Handler는 핸들러 정보를 담고 있는데 어떤 핸들러 매핑을 사용하는가에 따라 달라진다.

  • Handler Method
    스프링에서 일반적으로 사용되느 @Controller@RequestMapping을 활용한 핸들러 매핑을 사용하면 핸들러 정보로 HandlerMethod가 넘어온다.
if (handler instanceof HandlerMethod) {
	HandlerMethod hm = (HandlerMethod) handler;
 }
  • ResourceHttpRequestHandler
    /resources/static과 같은 정적 리소스가 호출되는 경우

Configuration - 인터셉터 등록

인터셉터를 등록하기 위해서는 WebMvcConfigurer를 구현해야한다.

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

WebMvcConfigurer가 제공하는 addInterceptors 함수를 통해 내가 만든 인터셉터 정보를 추가하면 된다.

  • addInterceptor(): 인터셉터를 등록
  • order(1): 인터셉터 호출 순서 등록. 1부터 시작.
  • addPathPatterns("/**"): 인터셉터를 거칠 URL패턴을 등록한다.
  • excludePathPatterns(): 위에 addPathPatterns에서 /**가 모든 경로를 의미한다. 필터에서 사용한 /*와 표현 방식이 다르다. 따라서 등록한 경로 중에서 인터셉터를 거치지 않을 URL패턴을 등록하는 함수이다.

로그인 인증 처리

클라이언트의 요청이 컨트롤러에 가기 전에 로그인을 한 사용자인지 확인하고 거르는 작업은 preHandle에서 하는 것이 적절해 보인다. session을 이용한 로그인 처리를 사용했다는 가정하에 코드를 작성해보면 다음과 같다.

public class loginCheckInterceptor implements HandlerInterceptor {
	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object Handler) throws Exception {
    	String requestURI = request.getRequestURI();
        HttpSession session = request.getSession(false);
        
        if (session == null || session.getAttribute("내가정한세션이름") == null)
        {
        	response.sendRedirect("/login?redirectURL=" + requestURI);
            return false;
		}
        return true;
	}

차례대로 요청이 들어온 URL에 대한 정보를 알아내고 이어서 세션에 대한 정보를 알기 위해 세션을 받았다. 로직대로 세션이 없거나 세션에 대한 정보가 없으니 로그인을 안한 사용자로 판단되어 /login페이지로 리다이렉트한다. 이 때 쿼리 파라미터로 클라이언트가 원했던 페이지 값을 보내줌으로서 로그인 페이지에서 로그인 성공시 쿼리 파라미터의 주소로 이동할 수 있게 도와주기 위한 로직이다.

중요한 것은 return값인데 false를 받게되면 이 요청은 더이상 컨트롤러까지 진행하지 못하고 response하게 된다. 다른 정보 없이 response에 리다이렉트 정보를 넘겨주었다. 반대로 true값이라면 필터에서처럼 다음 인터셉터나 컨트롤러로 요청이 넘어간다.

정리

서블릿 필터와 스프링의 인터셉터 모두 웹과 관련한 공통 관심 사항을 처리하기 위한 기술이다. 요청의 순서 흐름에 있어 어디서 처리하는지에 따라 다르긴 하지만 스프링의 인터셉터가 좀 더 세밀하게 처리해주는 느낌이다. 그리고 URL패턴을 등록하는데 더 개발자 친화적인 느낌을 받았다. 앞으로 프로젝트를 진행한다면 스프링 인터셉터를 사용할 일이 좀 더 많아 보인다.

profile
열심히 성장 중인 백엔드

0개의 댓글