简体   繁体   English

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

[英]WebFilter bean invoked twice in a secured Spring Boot Webflux application

I am using Spring Boot 2.1.x with webflux and security.我正在使用带有 webflux 和安全性的 Spring Boot 2.1.x。 I define some beans of type AuthenticationWebFilter that are added to the MatcherSecurityWebFilterChain .我定义了一些AuthenticationWebFilter类型的 bean,它们被添加到MatcherSecurityWebFilterChain The problem is that since they are defined as beans, they are also added at the end of the filter chain so they are executed twice.问题在于,由于它们被定义为 bean,它们也被添加到过滤器链的末尾,因此它们被执行两次。

For Servlet applications we could use FilterRegistrationBean to avoid this:对于 Servlet 应用程序,我们可以使用FilterRegistrationBean来避免这种情况:

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

What would be the equivalent for reactive applications?反应式应用程序的等价物是什么?

In my case, I have to execute a custom logic stored in TestGatewayFilter to modify ServerWebExchange object at the end in SecurityWebFilterChain.就我而言,我必须执行存储在 TestGatewayFilter 中的自定义逻辑,以在 SecurityWebFilterChain 的末尾修改 ServerWebExchange 对象。 If we create a bean of TestGatewayFilter and let spring process it, we find that filter logic is invoked twice per request.如果我们创建一个TestGatewayFilter的bean并让spring处理它,我们发现每个请求都会调用过滤器逻辑两次。
I researched but didn't find a way to define FilterRegistrationBean in spring-webflux-security but found a different approach to the same while debugging.我研究了但没有找到在 spring-webflux-security 中定义 FilterRegistrationBean 的方法,但在调试时发现了一种不同的方法。

As a workaround, I created a custom bean of SecurityWebFilterChain and injected the filter at the end of the chain.作为一种解决方法,我创建了一个 SecurityWebFilterChain 的自定义 bean,并在链的末尾注入了过滤器。 To prevent the spring from injecting this filter twice, we remove the logic to create a bean of it.为了防止 spring 两次注入这个过滤器,我们删除了创建它的 bean 的逻辑。 Now, the filter logic is getting invoked once per request.现在,每个请求都会调用一次过滤器逻辑。

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();
}

In this I have used addFilterAfter () method to add my filter after the last filter to be executed in chain.在此,我使用addFilterAfter () 方法在要在链中执行的最后一个过滤器之后添加我的过滤器。

ServerHttpSecurity class provides 2 more methods to add a filter before another filter or at a specific location in the chain. ServerHttpSecurity 类提供了另外 2 个方法来在另一个过滤器之前或在链中的特定位置添加过滤器。 They take the same set of arguments taken by addFilterAfter() method and can be used in similar way:它们采用 addFilterAfter() 方法采用的相同参数集,并且可以以类似的方式使用:

addFilterBefore()
addFilterAt()

While debugging, this is the filter execution order in SecurityWebFilterChain:调试时,这是 SecurityWebFilterChain 中的过滤器执行顺序:

  1. ServerWebExchangeReactorContextWebFilter ServerWebExchangeReactorContextWebFilter
  2. HttpHeaderWriterWebFilter HttpHeaderWriterWebFilter
  3. CorsWebFilter CorsWeb过滤器
  4. ReactorContextWebFilter ReactorContextWebFilter
  5. AuthenticationWebFilter认证网页过滤器
  6. SecurityContextServerWebExchangeWebFilter SecurityContextServerWebExchangeWebFilter
  7. ServerRequestCacheWebFilter ServerRequestCacheWebFilter
  8. LogoutWebFilter登出网页过滤器
  9. ExceptionTranslationWebFilter ExceptionTranslationWebFilter
  10. AuthorizationWebFilter授权网页过滤器
  11. TestGatewayFilter测试网关过滤器

I my case I've created custom TokenExchangeFilter that implements org.springframework.web.server.WebFilter as a spring @Bean .我的情况我创建了自定义TokenExchangeFilter ,它将org.springframework.web.server.WebFilter为 spring @Bean Then I've tried to use it via @Autowire while configuring web flux security filter chain.然后我尝试在配置 Web 通量安全过滤器链时通过@Autowire使用它。

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

That way spring would use it twice.这样 spring 就会使用它两次。 To solve it I've instantiated TokenExchangeFilter manually in place (made TokenExchangeFilter not a spring bean).为了解决这个问题,我已经手动实例化了TokenExchangeFilter (使TokenExchangeFilter不是 spring bean)。

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

    return http.build();
  }

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

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