[스프링 MVC, 스프링 시큐리티] 디스패처 서블릿과 서블릿컨테이너, 그리고 필터체인

hyelim·2023년 6월 30일
2

Spring

목록 보기
3/6
post-custom-banner

디스패처 서블릿

자세한 내용을 알고싶으면 이 링크에서 확인해주세요

디스패처 서블릿이란? HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러(Front Controller)

과거에는 모든 서블릿을 URL 매핑을 위해 web.xml에 모두 등록해주어야 했지만, dispatcher-servlet이 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주고 공통 작업을 처리면서 상당히 편리하게 이용할 수 있게 되었다. 우리가 컨트롤러를 구현해두기만 하면 디스패처 서블릿가 알아서 적합한 컨트롤러로 위임을 해준다

디스패처 서블릿(DispatcherServlet)은 스프링 프레임워크에서 웹 애플리케이션의 요청을 처리하는 핵심 컨트롤러이다

디스패처 서블릿은 서블릿 컨테이너에 의해 생성되어 요청을 받고, 해당 요청을 처리할 컨트롤러에게 전달하고, 컨트롤러의 실행 결과를 기반으로 응답을 생성한다

디스패처 서블릿의 주요 역할은 다음과 같습니다:

  1. 요청의 분배: 디스패처 서블릿은 클라이언트로부터 들어오는 요청을 분석하여 어떤 컨트롤러가 해당 요청을 처리해야 하는지 결정합니다. 이를 위해 URL 매핑, 핸들러 매핑 등의 기준을 사용하여 적절한 컨트롤러를 선택합니다.
  2. 컨트롤러 실행: 디스패처 서블릿은 선택된 컨트롤러에게 요청을 전달하고, 컨트롤러의 실행을 호출합니다. 컨트롤러는 요청을 처리하고 필요한 비즈니스 로직을 수행합니다.
  3. 모델과 뷰 관리: 컨트롤러가 실행한 결과로부터 생성된 모델 데이터를 관리하고, 적절한 뷰를 선택하여 응답을 생성합니다. 디스패처 서블릿은 모델과 뷰를 조합하여 최종적인 응답을 생성하고 클라이언트에게 반환합니다.
  4. 예외 처리: 요청 처리 중 발생하는 예외를 적절히 처리하고, 예외 발생 시 적절한 에러 페이지로 리다이렉트하거나 오류 응답을 생성합니다.
  5. 다양한 웹 애플리케이션 기능 지원: 디스패처 서블릿은 스프링의 다양한 기능과 확장성을 제공합니다. 예를 들어, 인터셉터를 통한 요청 전처리, 로깅, 세션 관리, 멀티파트 파일 업로드 등의 기능을 지원합니다.

디스패처 서블릿은 스프링 MVC에서 중요한 역할을 담당하며, 웹 애플리케이션의 전체 요청 처리 과정을 통제하고 제어합니다.

서블릿컨테이너

서블릿이란

자세한 내용은 이 링크 를 참고해주세요

  • WebProgramming에서 Client의 요청을 처리
  • 그 결과를 다시 Client에게 전송하는 자바 프로그래밍 기술
  • Servlet 클래스의 구현 규칙을 따른다.

서블릿컨테이너

서블릿 컨테이너는 클라이언트로부터 들어오는 HTTP 요청을 처리하는 기능을 제공하는 런타임 환경이다(ex Tomcat)

서블릿 컨테이너는 웹 애플리케이션의 동작을 관리하고, 클라이언트로부터 요청이 들어올 때마다 해당 요청을 처리할 서블릿에게 전달한다.

서블릿 컨테이너는 요청이 들어올 때마다 다음과 같은 순서로 작업을 수행한다:

  1. 클라이언트로부터 요청이 들어오면, 서블릿 컨테이너는 해당 요청을 처리하기 위한 적절한 서블릿을 선택합니다. 이때 서블릿 매핑 정보에 따라 URL 패턴 등을 기준으로 적절한 서블릿을 찾습니다.
  2. 서블릿 컨테이너는 선택된 서블릿에게 요청을 전달합니다. 이때 서블릿은 service() 메서드를 통해 요청을 처리하고, 필요에 따라 doGet(), doPost() 등의 메서드를 호출합니다.
  3. 서블릿은 요청에 대한 처리를 수행하고, 필요한 작업을 수행한 후에 응답을 생성합니다. 응답은 서블릿 컨테이너로 반환됩니다.
  4. 서블릿 컨테이너는 받은 응답을 클라이언트로 전송합니다.

디스패처 서블릿 전에 수행되는 필터체인

Filter 란?

사실 필터는 스프링의 독자적인 기능이 아닌 자바 서블릿에서 제공하는 기능이다

스프링에서 Filter는 요청이 DispatcherServlet에 의해 다뤄지기 전, 후에 동작한다

또한 Filter는 FilterChain(필터 체인)을 통해 여러 필터가 연쇄적으로 동작하게 할 수 있다

Filter의 사용처

필터는 주로 요청에 대한 인증, 권한 체크 등을 하는데에 쓰인다.구체적으로 들어온 요청이 DispatcherServlet에 전달되기 전에 헤더를 검사해 인증 토큰이 있는지 없는지, 올바른지 올바르지 않은지 등을 검사하는 작업에 사용된다.

필터체인

필터 체인은 서블릿 컨테이너가 서블릿에게 요청을 전달하기 전에 요청을 가로채고 필터링하는 역할을 합니다. 필터는 서블릿의 앞단에서 요청과 응답을 처리하는데 사용되며, 서블릿에 도달하기 전에 추가적인 작업을 수행할 수 있습니다.

서블릿 컨테이너는 요청이 들어오면 등록된 필터 체인을 순서대로 실행합니다. 각 필터는 요청을 처리하고, 다음 필터에게 요청을 전달하거나 서블릿에게 전달할 수 있습니다. 이를 통해 필터 체인은 요청 전후에 필요한 전처리나 후처리 작업을 수행할 수 있습니다.

결론적으로, 서블릿 컨테이너는 필터 체인을 통해 요청을 서블릿으로 전달하여 처리합니다. 필터는 요청을 가로채고 필터링하는 역할을 수행하며, 서블릿은 실제 요청 처리를 담당합니다. 이를 통해 클라이언트의 요청을 서블릿으로 전달하기 전에 필터에서 추가적인 작업을 수행할 수 있습니다.

스프링에서의 필터사용법

그럼 이제 스프링에서 필터를 어떻게 사용하는지 알아보겠습니다.

먼저 필터 클래스를 만들어야 하는데 필터 클래스는 servlet의 Filter 인터페이스를 구현하여 만들 수 있습니다.

public class FirstFilter implements Filter {}

필터 인터페이스는 3가지 메소드를 갖고 있는데 각각 다음과 같습니다.

  1. init() : 필터 가 생성될 때 수행되는 메소드
  2. doFilter() : Request, Response가 필터를 거칠 때 수행되는 메소드
  3. destroy() : 필터가 소멸될 때 수행되는 메소드

개발하면서 궁금한 점

개발하면서 토큰 인증관련 필터가 시큐리티설정에서 인증 처리를 필요없게 한 주소에 대해서는 동작하지 않을 것이라 생각했지만 동작하였다.

해결!!

위에서 정리한 내용을 보면 일반적으로 필터는 디스패처 서블릿 이전에 실행되기 때문에 모든 요청에 대해 실행되기에 그런 것으로 알 수 있었다.

그러나 실제로 필터에서 인증 처리를 수행하는 경우, 인증이 필요하지 않은 주소에 대해서는 필터에서 해당 요청을 건너뛰고 다음 필터 또는 서블릿으로 진행하도록 구현할 수 있다고한다.

이를 위해 필터 내부에서 요청의 주소를 확인하고, 인증이 필요하지 않은 주소에 대해서는 필터의 로직을 실행하지 않고 다음 필터로 넘어가게 처리하면된다.

아래는 해당 코드의 일부이다

@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 에 이 필터를 거치지 않을 주소를 적으면 될 것이다.

https://gardeny.tistory.com/35

profile
기록용
post-custom-banner

1개의 댓글

comment-user-thumbnail
2024년 9월 6일

NullAuthorities 찾다가 방문하였는데 잘 정리해주셨네요! 감사합니다 ㅎㅎ

답글 달기