자세한 내용을 알고싶으면 이 링크에서 확인해주세요
디스패처 서블릿이란? HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러(Front Controller)
과거에는 모든 서블릿을 URL 매핑을 위해 web.xml에 모두 등록해주어야 했지만, dispatcher-servlet이 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주고 공통 작업을 처리면서 상당히 편리하게 이용할 수 있게 되었다. 우리가 컨트롤러를 구현해두기만 하면 디스패처 서블릿가 알아서 적합한 컨트롤러로 위임을 해준다
디스패처 서블릿(
DispatcherServlet
)은 스프링 프레임워크에서 웹 애플리케이션의 요청을 처리하는 핵심 컨트롤러이다
디스패처 서블릿은 서블릿 컨테이너에 의해 생성되어 요청을 받고, 해당 요청을 처리할 컨트롤러에게 전달하고, 컨트롤러의 실행 결과를 기반으로 응답을 생성한다
디스패처 서블릿의 주요 역할은 다음과 같습니다:
디스패처 서블릿은 스프링 MVC에서 중요한 역할을 담당하며, 웹 애플리케이션의 전체 요청 처리 과정을 통제하고 제어합니다.
자세한 내용은 이 링크 를 참고해주세요
서블릿 컨테이너는 클라이언트로부터 들어오는 HTTP 요청을 처리하는 기능을 제공하는 런타임 환경이다(ex Tomcat)
서블릿 컨테이너는 웹 애플리케이션의 동작을 관리하고, 클라이언트로부터 요청이 들어올 때마다 해당 요청을 처리할 서블릿에게 전달한다.
서블릿 컨테이너는 요청이 들어올 때마다 다음과 같은 순서로 작업을 수행한다:
service()
메서드를 통해 요청을 처리하고, 필요에 따라 doGet()
, doPost()
등의 메서드를 호출합니다.사실 필터는 스프링의 독자적인 기능이 아닌 자바 서블릿에서 제공하는 기능이다
스프링에서 Filter는 요청이 DispatcherServlet에 의해 다뤄지기 전, 후에 동작한다
또한 Filter는 FilterChain(필터 체인)을 통해 여러 필터가 연쇄적으로 동작하게 할 수 있다
필터는 주로 요청에 대한 인증, 권한 체크 등을 하는데에 쓰인다.구체적으로 들어온 요청이 DispatcherServlet에 전달되기 전에 헤더를 검사해 인증 토큰이 있는지 없는지, 올바른지 올바르지 않은지 등을 검사하는 작업에 사용된다.
필터 체인은 서블릿 컨테이너가 서블릿에게 요청을 전달하기 전에 요청을 가로채고 필터링하는 역할을 합니다. 필터는 서블릿의 앞단에서 요청과 응답을 처리하는데 사용되며, 서블릿에 도달하기 전에 추가적인 작업을 수행할 수 있습니다.
서블릿 컨테이너는 요청이 들어오면 등록된 필터 체인을 순서대로 실행합니다. 각 필터는 요청을 처리하고, 다음 필터에게 요청을 전달하거나 서블릿에게 전달할 수 있습니다. 이를 통해 필터 체인은 요청 전후에 필요한 전처리나 후처리 작업을 수행할 수 있습니다.
결론적으로, 서블릿 컨테이너는 필터 체인을 통해 요청을 서블릿으로 전달하여 처리합니다. 필터는 요청을 가로채고 필터링하는 역할을 수행하며, 서블릿은 실제 요청 처리를 담당합니다. 이를 통해 클라이언트의 요청을 서블릿으로 전달하기 전에 필터에서 추가적인 작업을 수행할 수 있습니다.
그럼 이제 스프링에서 필터를 어떻게 사용하는지 알아보겠습니다.
먼저 필터 클래스를 만들어야 하는데 필터 클래스는 servlet의 Filter 인터페이스를 구현하여 만들 수 있습니다.
public class FirstFilter implements Filter {}
필터 인터페이스는 3가지 메소드를 갖고 있는데 각각 다음과 같습니다.
개발하면서 토큰 인증관련 필터가 시큐리티설정에서 인증 처리를 필요없게 한 주소에 대해서는 동작하지 않을 것이라 생각했지만 동작하였다.
위에서 정리한 내용을 보면 일반적으로 필터는 디스패처 서블릿 이전에 실행되기 때문에 모든 요청에 대해 실행되기에 그런 것으로 알 수 있었다.
그러나 실제로 필터에서 인증 처리를 수행하는 경우, 인증이 필요하지 않은 주소에 대해서는 필터에서 해당 요청을 건너뛰고 다음 필터 또는 서블릿으로 진행하도록 구현할 수 있다고한다.
이를 위해 필터 내부에서 요청의 주소를 확인하고, 인증이 필요하지 않은 주소에 대해서는 필터의 로직을 실행하지 않고 다음 필터로 넘어가게 처리하면된다.
아래는 해당 코드의 일부이다
@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationProcessingFilter extends OncePerRequestFilter {
private static final StringNO_CHECK_URL= "/login";
private final JwtService jwtService;
private final UserRepository userRepository;
/**
* Spring Security에서 인증된 사용자의 권한 정보(GrantedAuthority)를 매핑할 때 사용하는 인터페이스
*이 인터페이스는UserDetailsService를 통해 가져온 사용자 정보를 기반으로UserDetails객체를 생성할 때 사용되며,이 과정에서 사용자의 권한 정보를 매핑하는 역할을 수행
*사용자 인증만 수행하고 권한 체크를 하지 않는 경우에NullAuthoritiesMapper를 사용
* NullAuthoritiesMapper는GrantedAuthoritiesMapper의 구현체
*/
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getRequestURI().equals(NO_CHECK_URL)) {
filterChain.doFilter(request, response); // "/login" 요청이 들어오면, 다음 필터(CustomJsonUsernamePasswordAuthenticationFilter)호출
return; // return으로 이후 현재 필터 진행 막기 (안해주면 아래로 내려가서 계속 필터 진행시킴)
}
NO_CHECK_URL 에 이 필터를 거치지 않을 주소를 적으면 될 것이다.
NullAuthorities 찾다가 방문하였는데 잘 정리해주셨네요! 감사합니다 ㅎㅎ