WebFilter bean 在安全的 Spring Boot Webflux 应用程序中调用了两次

Posted

技术标签:

【中文标题】WebFilter bean 在安全的 Spring Boot Webflux 应用程序中调用了两次【英文标题】:WebFilter bean invoked twice in a secured Spring Boot Webflux application 【发布时间】:2019-12-14 22:16:42 【问题描述】:

我正在使用带有 webflux 和安全性的 Spring Boot 2.1.x。我定义了一些AuthenticationWebFilter 类型的bean,它们被添加到MatcherSecurityWebFilterChain。问题是,由于它们被定义为 bean,它们也被添加到过滤器链的末尾,因此它们被执行了两次。

对于 Servlet 应用程序,我们可以使用 FilterRegistrationBean 来避免这种情况:

@Bean
    fun someFilterRegistrationBean() 
        val frb = FilterRegistrationBean(xxx)
        frb.setEnabled(false)
        return frb
    

响应式应用程序的等价物是什么?

【问题讨论】:

【参考方案1】:

在我的例子中,我必须执行存储在 TestGatewayFilter 中的自定义逻辑来修改 SecurityWebFilterChain 中最后的 ServerWebExchange 对象。如果我们创建一个 TestGatewayFilter 的 bean 并让 spring 处理它,我们会发现每个请求都会调用两次过滤器逻辑。 我进行了研究,但没有找到在 spring-webflux-security 中定义 FilterRegistrationBean 的方法,但在调试时发现了一种不同的方法。 作为一种解决方法,我创建了一个 SecurityWebFilterChain 的自定义 bean,并在链的末尾注入了过滤器。为了防止 spring 两次注入这个过滤器,我们删除了创建它的 bean 的逻辑。现在,每个请求都会调用一次过滤器逻辑。

public class TestGatewayFilter implements WebFilter 
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) 
        // To-Do logic
    


@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) 
    http.addFilterAfter(new TestGatewayFilter(), SecurityWebFiltersOrder.AUTHORIZATION)
            .authorizeExchange()
            .anyExchange().authenticated();
    return http.build();

在此我使用 addFilterAfter() 方法将我的过滤器添加到要在链中执行的最后一个过滤器之后。 ServerHttpSecurity 类提供了另外 2 种方法来在另一个过滤器之前或在链中的特定位置添加一个过滤器。它们采用 addFilterAfter() 方法采用的相同参数集,并且可以以类似的方式使用:

addFilterBefore()
addFilterAt()

在调试时,这是SecurityWebFilterChain中的过滤器执行顺序:

    ServerWebExchangeReactorContextWebFilter HttpHeaderWriterWebFilter CorsWebFilter ReactorContextWebFilter 身份验证WebFilter SecurityContextServerWebExchangeWebFilter ServerRequestCacheWebFilter 注销WebFilter ExceptionTranslationWebFilter AuthorizationWebFilter TestGatewayFilter

【讨论】:

【参考方案2】:

在我的情况下,我创建了自定义TokenExchangeFilter,将org.springframework.web.server.WebFilter 实现为弹簧@Bean。然后我尝试通过@Autowire 使用它,同时配置网络通量安全过滤器链。

  @Bean
  SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) 
    http
        // ...
        .and()
          .addFilterAfter(tokenExchangeFilter, SecurityWebFiltersOrder.AUTHENTICATION);
    return http.build();
  

这样 spring 会使用它两次。为了解决这个问题,我手动实例化了TokenExchangeFilter(使TokenExchangeFilter不是spring bean)。

  @Bean
  SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) 
    http
        // ...
        .and()
          .addFilterAfter(new TokenExchangeFilter(authClientService), SecurityWebFiltersOrder.AUTHENTICATION);

    return http.build();
  

【讨论】:

以上是关于WebFilter bean 在安全的 Spring Boot Webflux 应用程序中调用了两次的主要内容,如果未能解决你的问题,请参考以下文章

使用弹簧安全与自定义过滤器的优势?

NoSuchMethodError: org.springframework.beans.factory.xml.XmlReaderContext.getEnvironment()Lorg/sprin

Spring Bean的生命周期

我正在尝试在我的 sprin 启动应用程序中应用 auth0 安全性,但它会引发错误

在 Web 过滤器中访问会话范围的 JSF 托管 bean

ssm开发经历汇总