禁用webfilter的自动注册

am46iovg  于 2021-07-16  发布在  Java
关注(0)|答案(1)|浏览(439)

在springboot2.4应用程序中,我有两个 SecurityWebFilterChain s。对于其中的一个,我想补充一些 WebFilter 通过addfilterbefore()调用。

@Configuration
@EnableWebFluxSecurity
class WebSecurityConfig {

    @Bean
    fun filter1(service: Service): WebFilter = Filter1(service)

    @Bean
    fun filter2(component: Component): WebFilter = Filter2(component)

    @Bean
    @Order(1)
    fun apiSecurityConfiguration(
        http: ServerHttpSecurity,
        filter1: WebFilter,
        filter2: WebFilter
    ): SecurityWebFilterChain = http
        .securityMatcher(pathMatchers("/path/**"))
        .addFilterBefore(filter1, SecurityWebFiltersOrder.AUTHENTICATION)
        .addFilterAt(filter2, SecurityWebFiltersOrder.AUTHENTICATION)
        .build()

    @Bean
    @Order(2)
    fun actuatorSecurityConfiguration(
        http: ServerHttpSecurity,
        reactiveAuthenticationManager: ReactiveAuthenticationManager
    ): SecurityWebFilterChain = http
        .securityMatcher(pathMatchers("/manage/**"))
        .authenticationManager(reactiveAuthenticationManager)
        .httpBasic { }
        .build()
}

但是 WebFilter s被创建为bean,它们被自动注册并应用于所有请求,似乎在安全链之外。
对于servlet过滤器,可以使用 FilterRegistrationBean (参见spring引导文档)。
有没有类似的方法 WebFilter s、 或者我必须添加额外的网址过滤到这些过滤器?

u0njafvf

u0njafvf1#

为了找到一个解决方案,我们首先必须深入研究spring的工作原理及其内部结构。
所有类型的bean WebFilter 自动添加到主web处理过滤器链。
有关以下主题,请参阅spring boot文档:
在应用程序上下文中找到的webfilterbean将自动用于筛选每个交换。
因此,即使您希望它们仅应用于特定的spring安全过滤器链,也会发生这种情况。
(imho,重新使用 Filter 或者 WebFilter 接口,而不是具有相同签名的特定于安全性的内容。)
在代码中,相关部分位于SpringWeb的webhttphandlerbuilder中

public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
    // ...

    List<WebFilter> webFilters = context
            .getBeanProvider(WebFilter.class)
            .orderedStream()
            .collect(Collectors.toList());
    builder.filters(filters -> filters.addAll(webFilters));

    // ...
}

反过来,在spring引导的httphandlerautoconfiguration中调用它来创建主httphandler。

@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
    HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
    // ...
    return httpHandler;
}

为了防止这些过滤器应用于所有的交换,可以简单地不将它们创建为bean,而是手动创建它们,如上面的注解所示。然后beanprovider将找不到它们,也不会将它们添加到httphandler。但是,您离开了ioc国家,并失去了过滤器的自动配置。当这些过滤器变得更复杂或有很多过滤器时,这并不理想。
因此,我的解决方案是手动配置 HttpHandler 对于我的应用程序,它不会将特定于安全性的筛选器添加到全局筛选器链。
为了实现这一点,我首先为我的过滤器声明一个标记接口。

interface NonGlobalFilter

class MySecurityFilter : WebFilter, NonGlobalFilter {
  // ...
}

然后,在创建自定义httphandler的地方需要一个配置类。方便的是,webhttphandlerbuilder提供了一种方法,可以与使用者一起操作其过滤器列表。
这将阻止spring引导在httphandleratoconfiguration中使用自己的httphandler,因为它带有注解 @ConditionalOnMissingBean(HttpHandler.class) .

@Configuration
class WebHttpHandlerConfiguration(
    private val applicationContext: ApplicationContext
) {
    @Bean
    fun httpHandler() = WebHttpHandlerBuilder
        .applicationContext(applicationContext)
        .filters {
            it.removeIf {
                webFilter -> webFilter is NonGlobalFilter
            }
        }
        .build()
}

就这样!像往常一样,spring提供了很多现成的有用的默认值,但是当它妨碍您的时候,会有一种方法根据需要对其进行调整。

相关问题