【问题标题】:Filter order in spring-bootspring-boot中的过滤顺序
【发布时间】:2014-11-15 11:06:31
【问题描述】:

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

@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public UserInsertingMdcFilter userInsertingMdcFilter() {
    return new UserInsertingMdcFilter();
}

这也没有用:

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

【问题讨论】:

  • @Order(Ordered.LOWEST_PRECEDENCE + 100) 将不起作用,因为 Ordered.LOWEST_PRECEDENCE = Integer.Max 和 Integer.Max + 100 = 某个负数,这意味着非常高的优先级
  • @Ralph - 我也尝试了事件@Order(Ordered.LOWEST_PRECEDENCE),但没有成功。
  • 什么版本的 Spring Boot?你试过 1.1.7 吗?
  • @DaveSyer,我试过了,没区别

标签: java spring spring-mvc spring-boot


【解决方案1】:

来自 Spring 的伙计们再次提供帮助。见https://github.com/spring-projects/spring-boot/issues/1640https://jira.spring.io/browse/SEC-2730

Spring Security 没有在过滤器 bean 上设置它的顺序 创建。这意味着,当 Boot 正在创建一个 FilterRegistrationBean ,它获取默认顺序是 LOWEST_PRECEDENCE。

如果你想让你自己的过滤器去寻找 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;
}

【讨论】:

  • 鉴于HIGHEST_PRECEDENCE = -2147483648LOWEST_PRECEDENCE = 2147483647 我会假设最低优先级会排在最后?一切都会先于它
  • 它应该排在最后。来自@Order 的JavaDoc:较低的值具有较高的优先级。默认值为 Ordered.LOWEST_PRECEDENCE,表示最低优先级(输给任何其他指定的订单值)。
  • @OrangeDog 优先级!= 优先级
  • @Irxw 加一表示具有最高优先级的最低值!
【解决方案2】:

这已在 Spring Boot 1.2 中修复。安全链现在默认订购0

也可以通过属性设置:

security.filter-order=0 # Security filter chain order.

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

【讨论】:

  • 在 Spring Boot 1.3.x 中它是 SecurityProperties.DEFAULT_FILTER_ORDERFilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100 或者只是 -100
  • 在 Spring Boot 2.1.x => spring.security.filter.order=-100
【解决方案3】:

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

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

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

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

0: WebAsyncManagerIntegrationFilter
1: SecurityContextPersistenceFilter
2: HeaderWriterFilter
...

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

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

在我的例子中,我希望我的自定义日志过滤器在链中排在第一位(我的代码 sn-p 是 Kotlin,我将把 Java 实现留给你):

override fun configure(http: HttpSecurity) {
    http
        .addFilterBefore(MyCustomLoggingFilter(), WebAsyncManagerIntegrationFilter::class.java)
        .authorizeRequests()
        .antMatchers(
        ...
        )
}

第 3 步:盈利!

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

希望这对其他人有帮助。

【讨论】:

  • 谢谢。这对我的调试很有帮助。
【解决方案4】:

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

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

【讨论】:

    【解决方案5】:

    在你的第一种情况下,这是一个错误配置,spring的文档有特别提醒:

    您不能通过使用 @Order 注释其 bean 方法来配置过滤器的顺序。

    您可以从中找到:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-embedded-container-servlets-filters-listeners-beans

    【讨论】:

      【解决方案6】:

      添加

      logging.level.web=debug

      在您的 application.properties 中,您可以看到已注册过滤器的详细信息,包括它们在 springboot onstartup 时的顺序和 URL 模式。

      【讨论】:

      猜你喜欢
      • 2016-11-04
      • 2022-07-29
      • 2016-07-05
      • 2014-07-25
      • 2017-11-03
      • 2014-04-22
      • 2018-01-15
      • 1970-01-01
      • 2022-01-23
      相关资源
      最近更新 更多