繁体   English   中英

spring-boot 中的过滤顺序

[英]Filter order in spring-boot

如何在 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;
}

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

Spring Security 不会在它创建的 Filter 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;
}

这在 Spring Boot 1.2 中得到了修复。 安全链现在默认为 order 0

也可以通过属性设置:

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

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

这是一个与 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 在所需位置插入过滤器

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

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

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

第 3 步:获利!

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

希望这可以帮助其他人。

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

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

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

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

你可以从这里找到: https : //docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-embedded-container-servlets-filters-listeners -豆子

添加

logging.level.web=调试

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM