[Spring Security] Filter와 FilterChain

zini9188·2023년 3월 15일
0

Spring Security

목록 보기
3/6

Filter와 Filter Chain

Filter

서블릿 필터는 서블릿 기반 애플리케이션의 엔드포인트에 요청이 도달하기 전에 중간에 요청을 가로챈 후 어떤 처리를 할 수 있도록 해주는 JAVA의 컴포넌트

필터의 처리가 완료되면 디스패처서블렛에서 클라이언트 요청을 핸들러에 매핑하기 위한 다음 작업을 진행한다.

Filter Chain

여러 개의 필터가 체인을 형성하고 있는 필터의 묶음

특성

서블릿 필터 체인은 요청 URI path를 기반으로 HttpServletRequest를 처리하는데 클라이언트가 서버 측 애플리케이션에 요청을 전송하면 서블릿 컨테이너는 요청 URI의 경로를 기반으로 어떤 필터와 어떤 서블릿을 매핑할지 결정한다.

  • 필터는 필터 체인안에서 순서를 지정할 수 있고, 지정한 순서에 따라 동작하게 할 수 있다.

  • 필터 체인에서 필터의 순서는 매우 중요하다.

  • 여러 개의 필터를 등록하고 순서를 지정하기

    • @Order 애너테이션이나, Ordered 인터페이스를 구현

    • FilterRegistrationBean 을 사용하여 명시적으로 필터의 순서를 지정

웹 요청에서의 서블릿 필터와 필터 체인의 역할

javax.servlet.Filter 인터페이스를 구현한 서블릿 필터는 웹 요청을 가로채 전처리를 할 수 있으며, 엔드 포인트에서 요청 처리가 끝난 후 응답에 대한 후처리 또한 가능하다.

하나 이상의 필터들을 연결하여 필터 체인을 구성할 수 있다.

Spring Security에서의 필터 역할

스프링 시큐리티에서는 필터를 통해 전처리 과정과 후처리 과정에서 보안 작업을 수행할 수 있다.

DelegatingFilterProxy

  • Filter 인터페이스를 구현하는 구현 클래스

  • 필터를 사용하는 시작점이다.

  • 서블릿 컨테이너 영역의 필터와 ApplicationContext에 Bean으로 등록된 필터들을 연결해주는 브릿지 역할

FilterChainProxy

  • 보안을 위한 작업을 처리하는 필터의 모음

  • 스프링 시큐리티의 필터를 사용하기 위한 진입점으로 보안 필터들이 필요한 작업을 수행

  • URL 별로 필터 체인을 등록할 수 있는데, 이때 필터 체인의 우선순위는 FilterChainProxy에 의해 결정되며 가장 먼저 매칭된 필터 체인을 사용

    • /api/**/** 필터 체인이 있고 /api/message URL이 들어오는 경우, 가장 먼저 매칭된 /api/** 필터 체인을 사용
    • /message/**/ URL의 경우, 가장 먼저 매칭되는 /** 필터 체인을 사용

Filter, Filter Chain의 구현

Filter 인터페이스

public class FirstFilter implements Filter {
     public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);  
        System.out.println("FirstFilter 생성됨");      
     }
     
     public void doFilter(ServletRequest request,
                          ServletResponse response,
                          FilterChain chain)
                          throws IOException, ServletException {  
 		System.out.println("========First 필터 시작========");
        chain.doFilter(request, response);
        System.out.println("========First 필터 종료========");
     }
     
     public void destroy() {
        System.out.println("FirstFilter Destory");
        Filter.super.destroy();
     }
  }
  • init() 메서드

    • 생성한 필터에 대한 초기화 작업을 진행
  • doFilter() 메서드

    • chain.doFilter() 이전에서 전처리 작업에 대해 구현

    • chain.doFilter() 이후에서 후처리 작업에 대해 구현

  • destroy() 메서드

    • 필터가 컨테이너에서 종료될 때 호출

    • 필터가 사용한 자원을 반납하는 처리 등의 로직을 작성

@Configuration
public class FilterConfiguration {

    @Bean
    public FilterRegistrationBean<FirstFilter> firstFilterRegister()  {
        FilterRegistrationBean<FirstFilter> registrationBean = new FilterRegistrationBean<>(new FirstFilter());
        return registrationBean;
    }
}

출력 결과

애플리케이션 실행 시

FirstFilter 생성됨

컨트롤러의 핸들러 메서드가 동작 시

=======First 필터 시작========
.. 핸들러 메서드의 처리
========First 필터 종료========

두개 이상의 필터가 존재하는 경우

 	@Bean
    public FilterRegistrationBean<FirstFilter> firstFilterRegister()  {
        FilterRegistrationBean<FirstFilter> registrationBean = new FilterRegistrationBean<>(new FirstFilter());
        registrationBean.setOrder(1);
        return registrationBean;
    }
	@Bean
    public FilterRegistrationBean<SecondFilter> secondFilterRegister()  {
        FilterRegistrationBean<SecondFilter> registrationBean = new FilterRegistrationBean<>(new SecondFilter());
        registrationBean.setOrder(2);
        return registrationBean;
    }

만약 두개 이상의 필터가 존재하면 configuration 클래스에서 해당 필터 내에 registrationBean.setOrder(1), registrationBean.setOrder(2)와 같이 번호를 지정하면 FirstFilter의 우선순위가 더 높게 지정되어 실행된다.

profile
백엔드를 지망하는 개발자

0개의 댓글