在一个spring-Boot2.4应用程序中,我有两个SecurityWebFilterChain,对于其中的一个,我想通过addFilterBefore()添加一些WebFilter。
@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是作为bean创建的,它们会自动注册并应用于所有请求,看起来像是在安全链之外。
对于servlet筛选器,可以使用FilterRegistrationBean禁用此注册(请参阅spring-boot documentation)。
reactive WebFilter有没有类似的方法,或者我必须在这些过滤器中添加额外的URL过滤?
发布于 2021-03-21 17:45:23
为了找到解决方案,我们首先必须更深入地研究spring是如何工作的,以及它的内部结构。
所有WebFilter类型的bean都会自动添加到主web处理筛选器链中。
有关该主题的信息,请参阅spring boot documentation:
在应用程序上下文中找到的
WebFilter beans将自动用于过滤每个交换。
因此,即使您希望它们仅应用于特定的spring-security过滤器链,也会发生这种情况。
(我的意思是,重用Filter或WebFilter接口,而不使用具有相同签名的特定于安全的东西,这是spring安全性的一点缺陷。)
在代码中,相关部分在spring-web的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-boot的HttpHandlerAutoConfiguration中调用它来创建主HttpHandler。
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
// ...
return httpHandler;
}为了防止将这些过滤器应用于所有交换,可以简单地不将它们创建为bean并手动创建它们,正如上面的注释中所建议的那样。则BeanProvider不会找到它们,也不会将它们添加到HttpHandler中。但是,您离开了IoC国家/地区并丢失了过滤器的自动配置。当这些过滤器变得更复杂,或者当你有很多过滤器时,这并不理想。
因此,我的解决方案是为我的应用程序手动配置一个HttpHandler,这不会将我的特定于安全的过滤器添加到全局过滤器链中。
为此,我首先为我的过滤器声明了一个marker interface。
interface NonGlobalFilter
class MySecurityFilter : WebFilter, NonGlobalFilter {
// ...
}然后,在创建自定义HttpHandler的位置需要一个配置类。方便的是,WebHttpHandlerBuilder有一个带有消费者的method to manipulate its filter list。
这将阻止spring-boot使用来自HttpHandlerAutoConfiguration的自己的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提供了许多开箱即用的有用默认设置,但当它阻碍您的方式时,将有一种方法可以根据需要对其进行调整。
https://stackoverflow.com/questions/66707864
复制相似问题