在spring-boot中过滤顺序

igo*_*igo 33 java spring spring-mvc spring-boot

如何在spring-boot中指定过滤器的顺序?我需要在Spring Security过滤器之后插入我的MDC过滤器.我几乎尝试了所有东西,但我的过滤器总是第一个 这不起作用:

@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public UserInsertingMdcFilter userInsertingMdcFilter() {
    return new UserInsertingMdcFilter();
}
Run Code Online (Sandbox Code Playgroud)

这也不起作用:

@Bean
public FilterRegistrationBean userInsertingMdcFilterRegistrationBean() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    UserInsertingMdcFilter userFilter = new UserInsertingMdcFilter();
    registrationBean.setFilter(userFilter);
    registrationBean.setOrder(Integer.MAX_VALUE);
    return registrationBean;
}
Run Code Online (Sandbox Code Playgroud)

igo*_*igo 40

来自Spring的人再次帮助.请参阅https://github.com/spring-projects/spring-boot/issues/1640https://jira.spring.io/browse/SEC-2730

Spring Security不会在它创建的Filter bean上设置顺序.这意味着,当Boot为其创建FilterRegistrationBean时,它将获得默认顺序LOWEST_PRECEDENCE.

如果您希望自己的Filter遵循Spring Security,您可以为Spring Security的过滤器创建自己的注册并指定顺序.

所以我的问题的答案是:

@Bean
public FilterRegistrationBean securityFilterChain(@Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) Filter securityFilter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
    registration.setOrder(Integer.MAX_VALUE - 1);
    registration.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
    return registration;
}

@Bean
public FilterRegistrationBean userInsertingMdcFilterRegistrationBean() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    UserInsertingMdcFilter userFilter = new UserInsertingMdcFilter();
    registrationBean.setFilter(userFilter);
    registrationBean.setOrder(Integer.MAX_VALUE);
    return registrationBean;
}
Run Code Online (Sandbox Code Playgroud)

  • 它应该放在最后。来自@Order 的 JavaDoc:*较低的值具有较高的优先级。默认值为 Ordered.LOWEST_PRECEDENCE,表示最低优先级(输给任何其他指定的订单值)。* (4认同)
  • 鉴于`HIGHEST_PRECEDENCE = -2147483648`和'LOWEST_PRECEDENCE = 2147483647`,我认为最低优先级会持续到最后?一切都会在它之前__? (2认同)
  • @OrangeDog Precedence!=优先级 (2认同)

Mik*_*ail 16

这在Spring Boot 1.2中得到修复.安全链现在默认为订购0.

它也可以通过属性设置:

security.filter-order=0 # Security filter chain order.
Run Code Online (Sandbox Code Playgroud)

https://github.com/spring-projects/spring-boot/issues/1640

  • 在Spring Boot 1.3.x中,它是`SecurityProperties.DEFAULT_FILTER_ORDER`并且是`FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100`或者只是`-100`. (3认同)
  • 在Spring Boot 2.1.x =>`spring.security.filter.order = -100`中 (3认同)

Nat*_*han 15

这是一个与 Spring Boot 2 / Spring Security 5 兼容的答案,它允许您将过滤器插入过滤器链中的任意位置。

我的用例是javax.servlet.Filter我想在任何 Spring Security 过滤器之前执行的自定义日志记录;但是,以下步骤应该允许您在现有 Spring 过滤器链中的任何位置放置过滤器:

步骤 1:找出现有设置中 Spring 过滤器的顺序。

你最喜欢的远程调试器连接到您的应用程序,并在设置断点doFilter(ServletRequest request, ServletResponse response)的方法org.springframework.security.web.FilterChainProxy。从 Spring Security 5.1.6 开始,即第 311 行。在您的调试器中,通过检查来找出现有的过滤器this.additionalFilters。在我的应用程序中,订单类似于:

0: WebAsyncManagerIntegrationFilter
1: SecurityContextPersistenceFilter
2: HeaderWriterFilter
...
Run Code Online (Sandbox Code Playgroud)

第 2 步:使用 Spring 的 WebSecurityConfigurerAdapter 和 HttpSecurity 在所需位置插入过滤器

您可能已经有了一个WebSecurityConfigurerAdapterwith@Override configure(HttpSecurity http)方法。HttpSecurity暴露addFilterBeforeaddFilterAfter方法允许您将过滤器相对于链中的现有类放置。您的过滤器(实例)是这些方法的第一个参数,您想要在之前或之后插入的过滤器的类是第二个参数。

就我而言,我希望我的自定义日志过滤器成为链中的第一个(我的代码片段是 Kotlin,我将 Java 实现留给您):

override fun configure(http: HttpSecurity) {
    http
        .addFilterBefore(MyCustomLoggingFilter(), WebAsyncManagerIntegrationFilter::class.java)
        .authorizeRequests()
        .antMatchers(
        ...
        )
}
Run Code Online (Sandbox Code Playgroud)

第 3 步:获利!

使用上面步骤 1 中描述的调试方法来验证您的过滤器是否位于过滤器链中的预期位置。

希望这可以帮助其他人。

  • 感谢您。这对我的调试很有帮助。 (3认同)

Yas*_*mez 5

请注意,Spring Security 过滤器链并不是过滤器的全部。事实上,有一个完整的(非安全)过滤器链在工作,其中一个过滤器是其中一个实例DelegatingFilterProxy(nomen est omen)委托给另一个名为的过滤器FilterChainProxy,该过滤器管理自己的过滤器子列表,所有过滤器都面向安全相关主题。此模式的优点是所有安全过滤器都位于一个位置并且彼此正确排序。但是,如果您需要在所有安全过滤器之前之后 执行过滤器,那么这对您没有任何帮助。虽然您确实可以通过选择该列表中的第一个或最后一个过滤器来使用对象进行配置,但这在逻辑上很奇怪,因为您的过滤器很可能与安全性完全无关。如果您设置断点,您将看到应用程序的整个过滤器链。如果您愿意,您甚至可以深入查找所有弹簧安全过滤器。然后就可以一一打开相关的类,找出它们的配置顺序。一旦您知道过滤器应该在哪里,您就可以对其进行注释。HttpSecurityDelegatingFilterProxy::doFilter(ServletRequest, ServletResponse, FilterChain)FilterChainProxy

例如,如果您需要配置日志过滤器,并且想要记录所有安全故障(需要在 之前FilterChainProxy),但还想要一个有用的跟踪 ID(需要在LazyTracingFilter其配置的默认顺序之后TraceHttpAutoConfiguration.TRACING_FILTER_ORDER = Ordered.HIGHEST_PRECEDENCE + 5),您可以使用以下方式注释您的过滤器@Order(Ordered.HIGHEST_PRECEDENCE + 6)