JWT를 이용한 회원 인증같은 공통된 로직을 처리하기 위해 Spring에서 어떤 것을 사용해야하는지 의문이 들었습니다. Spring에서는 공통된 작업을 처리하여 중복 코드를 제거할 수 있도록 많은 기능들을 제공하는데, 대표적인 필터(Filter) 와 인터셉터(Interceptor)의 개념과 차이에 대해 알아보려고 합니다.
Filter (필터)
필터는 스프링의 독자적인 기능이 아닌 자바 서블릿에서 제공하는 기능입니다. 디스패처 서블릿 (Dispatcher Servlet)에 요청이 전달되기 전/후 url 패턴에 맞는 모든 요청에 대해 부가작업을 처리할 수 있는 기능을 제공합니다.
여기서 Dispatcher Servlet 이란 !?
스프링에 가장 앞단에 존재하는 Front Controller로 모든 클라이언트의 요청을 먼저 받아 적합한 컨트롤러에 위임해주는 컨트롤러입니다.
즉, Filter는 스프링 컨테이너가 아닌 웹 컨테이너(서블릿 컨테이너)에 의해 관리가 되는 것이고, Dispatcher Servlet 전/후에 처리하는 것입니다.
Filter (필터) 구현하기
필터는 웹 애플리케이션에서 요청과 응답을 가로채서 처리하는 데 사용됩니다. 필터를 추가하기 위해서는 javax.servlet의 Filter 인터페이스를 구현해야하며, 이는 다음의 3가지 메소드를 가지고 있습니다.
- init 메소드
- doFilter 메소드
- destroy 메소드
1. init()
필터 객체를 초기화하고 서비스에 추가하기 위한 메소드입니다. 웹 컨테이너가 1회 메소드를 실행하고 필터 객체를 초기화 하면 이후 요청들은 doFilter를 통해 처리됩니다.
2. doFilter
실제 필터링 논리적인 로직을 처리하는 부분입니다. chain.doFilter(request, response)는 제어를 체인의 다음 필터 또는 서블릿으로 전달합니다. 컨트롤이 후속 필터 및 서블릿에서 반환된 후 필요한 경우 사후 처리 논리를 수행할 수 있습니다
3. destroy
필터 객체를 서비스에서 제거하고 사용하는 자원을 반환하기 위한 메소드입니다.
Interceptor (인터셉터)
필터(Filter)와 달리 Spring이 제공하는 기술로서, Dispatcher Servlet이 요청에 적합한 컨트롤러를 호출하기 전/후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공합니다.
즉, 인터셉터는 스프링 컨텍스트 안에서 동작합니다.
Dispatcher Servlet이 Handler Mapping을 통해 요청에 적합한 컨트롤러를 찾도록 하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려줍니다. 그래서 이 실행 체인은 1개 이상의 인터셉터가 등록되어 있다면
순차적으로 인터셉터를 거쳐 컨트롤러가 실행되도록 합니다.
인터셉터 구현하기
인터셉터를 추가하기 위해서는 HandlerInterceptor 인터페이스를 구현해야 하며, 이는 다음의 3가지 메소드를 가지고 있습니다.
- preHandle 메소드
- postHandle 메소드
- afterCompletion 메소드
1. PreHandle()
Controller 호출 전에 실행됩니다. 반환타입은 boolean 이며 true 일 때 다음 Handler 실행, false 시 컨트롤러로 요청이 전달되지 않습니다.
2. PostHandle()
Controller의 정상적인 호출 후에 실행됩니다. 컨트롤러에서 예외가 발생한다면 PostHandle() 메소드는 실행되지 않습니다.
3. afterCompletion()
뷰가 클라이언트에 응답을 전송한 뒤에 실행됩니다. 컨트롤러 실행 과정에서 예외가 발생한 경우 해당 예외가 afterCompletion()의 4번째 파라미터인 Exception으로 전달되어, 로그를 남기는 등의 후처리를 위해 사용될 수 있습니다.
필터(Filter) vs 인터셉터(Interceptor)의 차이 및 용도
관리되는 컨테이너의 차이
위에서 설명했듯이 필터와 인터셉터는 관리되는 영역이 다릅니다. 필터는 스프링 이전 영역에서 관리되지만, 인터셉터는 스프링 컨테이너 영역 안쪽에서 관리됩니다.
필터는 스프링이 처리해주는 내용을 적용 받을 수 없습니다. 이로 인하여 발생하는 대표적인 차이가 스프링에 의한 예외처리가 되지 않는다는 것을 예로 들 수 있습니다.
스프링의 예외 처리 여부
스프링을 사용해 개발 시, Controller에서 발생하는 예외를 처리하기 위해 ControllerAdvice와 ExceptionHandler를 이용한 예외처리 기능을 사용합니다.
하지만, 바로 위에서 설명했듯 Filter는 스프링의 예외처리가 되지 않습니다. 서블릿은 예외가 처리되기 기대했지만, 예외가 그대로 올라와서 예상치 못한 Exception을 만난 상황이고, 따라서 서버 내부에 문제가 있다고 판단하여 500 Status (Server Error)로 응답을 반환합니다.
Request/Response 객체 조작 가능 여부
필터는 Request와 Response를 조작할 수 있지만 인터셉터는 조작할 수 없습니다. 여기서 조작한다는 것은 내부 상태를 변경하는 것이 아니라 다른 객체로 교체한다는 의미입니다.
필터가 다음 필터를 호출하기 위해서는 필터 체이닝(다음 필터 호출)을 해주어야 하는데, 이때 Request/Response 객체를 넘겨주므로 우리가 원하는 Request/Response 객체를 넣어줄 수 있습니다.
인터셉터는 필터와 처리과정이 다릅니다. Dispatcher Servlet이 여러 인터셉터 목록을 가지고 있고, 반복문을 사용하여 순차적으로 실행합니다. 그리고 true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, false가 반환되면 요청이 중단됩니다. 그러므로 우리가 다른 Request/Response 객체를 넘겨줄 수 없습니다.
정리
필터(Filter)는 스프링 컨테이너 밖에서 실행되므로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리합니다.
인터셉터(Interceptor)는 스프링 컨테이너 안에서 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업을 처리합니다.
Java Servlet에서 제공하는 Filter는 비교적 단순하지만 (doFilter() 하나만 제공), Interceptor는 preHandle, postHandle, afterCompletion의 메소드를 통해 요청 시점에 따른 작업을 단계적으로 세분화가 가능합니다.
필터와 인터셉터의 용도 및 예시
필터
- 공통된 보안 및 인증/인가 관련 작업
- 모든 요청에 대한 로깅 또는 검사
- 이미지/데이터 압축 및 문자열 인코딩
- Spring과 분리되어야 하는 기능
인터셉터
- 세부적인 보안 및 인증/인가 공통 작업
- API 호출에 대한 로깅 또는 검사
- Controller로 넘겨주는 정보(데이터)의 가공
그래서 Filter와 Interceptor중 어떤걸 사용하면 될까요??
우리는 스프링을 통해 로직을 처리하므로 스프링에 의존적인 인터셉터를 사용하기로 하였습니다. JWT 유효성 검사 도중 401에예외를 발생시킨다거나, 회원 로직 도중 생기는 예외들을 처리해야 하기 때문입니다.
다음 포스팅에는 실제로 Controller에 존재하는 회원의 인증/인가 처리에 대한 많은 중복 로직 문제들을 Interceptor를 통해서 어떻게 해결하는지 포스팅해볼 예정입니다!!
출처
https://mangkyu.tistory.com/173
'BackEnd' 카테고리의 다른 글
세션 인증 방식과 토큰 인증 방식 (1) | 2023.07.13 |
---|---|
Interceptor 를 통해 회원 API 리팩토링하기 (1) | 2023.07.03 |
Message Queue (3) | 2023.04.27 |
티켓 예약 서비스의 대규모 트래픽 처리에 대한 고민 (1) | 2023.04.22 |
로그(Log) 확인해봤어?? 로그 제대로 알자 (5) | 2023.02.23 |