[Spring Security] 7. GenericFilterBean, OncePerRequestFilter

조성우·2024년 8월 14일

Spring Security

목록 보기
6/16
post-thumbnail

대부분의 필터는 GenericFilterBean, OncePerRequestFilter 두 가지의 추상 클래스를 기반으로 만들어지기 때문에, 두 추상 클래스에 대해 좀 더 자세히 알아보도록 하자.


SecurityFilterChain에 담겨 있는 필터는 GenericFilterBean 기반으로 구현된 필터가 있고, GenericFilterBean을 상속한 OncePerRequestFilter 기반으로 구현된 필터도 존재한다.

두 방식의 차이점은 무엇일까?


GenericFilterBean vs OncePerRequestFilter

기준은 클라이언트의 한 번의 요청에 대해서다.

GenericFilterBean은 내부적으로 동일한 필터를 여러 번 통과하더라도 통과한 수 만큼 내부 로직이 실행된다.
OncePerRequestFilter는 내부적으로 동일한 필터를 여러 번 통과하더라도 첫 한 번만 내부 로직이 실행된다.

OncePerRequestFilter에 대해서 대부분의 블로그들이 잘못된 내용을 전달하고 있다고 한다.

주로 redirect(302)를 주제로 OncePerRequestFilter가 한 번 동작된다고 말하는데 이는 틀린 내용이다. 302는 사용자에게 재요청을 보내라고 응답을 주기 때문에 사용자의 요청이 2번 보내지는 것과 동일하다.

즉, OncePerRequestFilter가 의미하는 동작을 이루기 위해서는 redirect 시에는 해당이 안되고 forward 상태만 해당 되는데 많은 블로그들은 302, redirect시 된다고 적혀 있다.


각 상태에 대해서 어떻게 동작이 되는가

  • forward 상태

한 번의 클라이언트 요청에 대해서 동일한 필터를 2번 탔지만 OncePerRequestFilter는 한 번 동작한다.


  • redirect 상태

redirect는 다른 경로로 재요청하라는 의미로 실제로 클라이언트가 2번 요청한 것으로 OncePerRequestFilter가 두 번 실행된다.


테스트

  • 확인을 위한 OncePerRequestFilter 작성
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 작성
public class CustomGeneriFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {


        System.out.println("CustomGenericFilter");

        chain.doFilter(request, response);
    }
}

  • SecurityConfig SecurityFilterChain에 등록
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
                .authorizeHttpRequests((auth) -> auth.anyRequest().permitAll());

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

        return http.build();
    }
}
  • 테스트 진행을 위한 컨트롤러 작성
@Controller
public class MainController {

    @GetMapping("/testfilterbefore")
    public String before() {

        return "forward:/testfilterafter";
        // return "redirect:/testfilterafter";
    }

    @GetMapping("/testfilterafter")
    @ResponseBody
    public String after() {

        return "hihihi";
    }
}

실행 결과

forward의 경우에는 "CustomOnceFilter"는 한 번 출력되었지만, redirect의 경우에는 재요청, 즉 2번의 요청으로 "CustomOnceFilter"가 2번 실행된 것을 확인할 수 있다.

0개의 댓글