Spring Security - Custom Filter

·2024년 6월 5일

Spring Security

목록 보기
11/13

유튜브 "개발자 유미"님 강의를 듣고 정리한 내용입니다.

Custom Filter

스프링 시큐리티에서 Custom Filter를 만들고 등록하기 위해서는 먼저 GenericFilterBean에 대해서 이해해야 한다.

Filter 상속

SecurityFilterChain에서 사용되는 시큐리티 필터는 스프링 빈으로 등록되어 관리된다. 서블릿 필터는 스프링 빈으로 관리되지 않기 때문에, Filter 클래스로부터 바로 스프링에서 관리되는 시큐리티 필터를 만들 수는 없다.

스프링에서 관리되는 시큐리티 필터를 만들 수 있도록, 이미 스프링에서 GenericFilterBean이라는 추상 클래스를 제공한다.

GenericFilterBean 클래스는 추상 클래스로서 서블릿 필터 클래스인 Filter의 구현체이다. 자바 서블릿 영역에서 스프링 영역에 접근할 수 있도록 작성되어 있다.

GenericFilterBean을 상속하는 OncePerRequestFilter 클래스도 시큐리티 필터를 만들기 위해 사용되는 추상 클래스이다.

GenericFilterBean vs OncePerRequestFilter

둘 다 스프링 시큐리티의 Custom Filter를 만들 수 있는 추상 클래스이다.

GenericFilterBean을 상속하는 클래스를 만들면, doFilter() 메서드를 오버라이딩하도록 되어있다.

public class CustomGenericFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("CustomGenericFilter");

        chain.doFilter(request, response);
    }
}

파라미터로 ServletRequest, ServletResponse, FilterChain을 가지고 있다 .

doFilter() 메서드 안에 내부 로직을 작성한 후, 반드시 필터 체인의 다음 필터를 호출할 수 있도록, chain.doFilter(request, response)를 호출해야 한다.


OncePerRequestFilter 역시 GenericFilterBean을 상속하는 추상 클래스이므로, 구현 클래스를 만들면 doFilterInternal() 메서드를 오버라이딩 하도록 되어있다.

public class CustomOnceFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println("CustomOnceFilter");

        filterChain.doFilter(request, response);
    }
}

GenericFilterBean에서 doFilter()를 오버라이딩 했던 것과 마찬가지로, 내부 로직 작성 후 filterChain.doFilter()를 호출하면 된다.

OncePerRequestFilter는 내부에서 어떤 요청이 이미 filter 되었는지 확인한다. 이는 getAlreadyFitleredAttributeName()으로 처리된다.

그래서 이미 Filter 된 요청에 대해서는 다시 필터를 처리하지 않는다. 즉, 필터 체인의 doFilter()를 호출하지 않게 되고 필터의 내부 로직은 수행되지 않는다.

이로써 GenericFilterBeanOncePerRequestFilter의 차이를 알 수 있다.
GenericFilterBean은 한 번의 요청에 대해서 여러 번의 filter 처리(필터 체인의 수행)가 될 수 있지만, OncePerRequestFilter는 한 번의 요청에 대해서 단 한 번만 filter 처리 된다.

OncePerRequestFilter 주의 사항

어떤 요청에서 forward가 되면, 이는 서버 내부에서 처리되기 때문에 한 번의 요청만 수행된다.

이와 같은 경우에 GenericFilterBean은 forward 전/후로 두 번의 filter 처리를 하게 되지만, OncePerRequestFilter는 단 한 번의 filter 처리를 수행하게 된다.

하지만 어떤 요청에서 redirect(302코드) 되면, 사용자에게 재요청을 보내라고 응답하기 때문에, 총 2번의 사용자 요청이 수행된다.

이 경우에도 GenericFilterBean은 redirect 전/후로 두 번의 filter 처리를 하게 된다.
OncePerRequestFilter는 요청 당 한 번의 filter 처리를 하기 때문에 요청마다 filter 처리를 하게 된다. 그래서 결론적으로 redirect 시에는 2번의 filter 처리를 하게 된다.

즉, OncePerRequestFilter가 의미하는 동작을 이루기 위해서는 rediret시에는 해당이 안되고, forward시에만 해당된다.

Custom Filter 등록

SecurityFilterChain의 빈 등록 과정에서 Custom Filter를 등록할 수 있다.

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((auth) -> auth.anyRequest().permitAll());

        http
                .addFilterAfter(new CustomGenericFilter(), LogoutFilter.class);

        http
                .addFilterAfter(new CustomOnceFilter(), LogoutFilter.class);

        return http.build();
    }

위와 같이 addFilterAfter() 메서드를 사용하여 Custom Filter를 등록할 수 있다.
첫 파라미터로는 Custom Filter 구현체의 객체를, 두번째 파라미터로는 등록하는 Custom Filter의 바로 전 필터를 지정해주면 된다.

profile
티스토리로 블로그 이전합니다. 최신 글들은 suhsein.tistory.com 에서 확인 가능합니다.

0개의 댓글