我有一个
BearerTokenAuthenticationFilter
,它是通过 SecurityFilterChain
注册的。此外,还有一个通过 ProfileSynchronizationFilter
注册的 FilterRegistrationBean
。
BearerTokenAuthenticationFilter
需要在ProfileSynchronizationFilter
之前执行。现在却发生相反的情况。
我的理解是
SecurityFilterChain
中的过滤器是由DelegatingFilterProxy
执行的。所以,我认为 DelegatingFilterProxy
必须相对于 ProfileSynchronizationFilter
进行排序。但是,我不确定这是否是正确的方法 - 甚至不确定如何做到这一点。
摘自 Spring 文档:
https://docs.spring.io/spring-security/reference/servlet/architecture.html#servlet-filterchainproxy
如何解决此排序问题,以便
BearerTokenAuthenticationFilter
在 ProfileSynchronizationFilter
之前执行?
SecurityFilterChain
的配置:
@Bean
@Order(2)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.requestMatchers()
.antMatchers(listOfSecuredResources)
.and()
.authorizeRequests()
.antMatchers(listOfSecuredResources)
.fullyAuthenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.and()
.addFilter(jwtAuthenticationFilter)
.anonymous()
.disable();
return http.build();
}
ProfileSynchronizationFilter
的配置:
@Bean
public FilterRegistrationBean registerProfileSynchronizationFilter(ProfileSynchronizationFilter profileSynchronizationFilter) {
FilterRegistrationBean reg = new FilterRegistrationBean(profileSynchronizationFilter);
reg.setOrder(6);
return reg;
}
原帖中发布的插图很好地概述了过滤器和安全过滤器。 Spring 将
DelegatingFilterProxy
(springSecurityFilterChain) 安装为过滤器。正如类名所示,此过滤器将过滤委托给安全过滤器。
安全过滤器不能相对于常规过滤器进行订购。安全过滤器只能相对于其他安全过滤器进行订购。
要了解 Spring Boot 项目中的常规过滤器和安全过滤器,您可以使用下面的类,它将在应用程序启动时列出所有过滤器。
根据此列表,我能够解决过滤器排序问题。
对于我在原始帖子中描述的具体问题,执行顺序不可预测的原因之一是安全过滤器暴露为
Bean
。因此,Spring 安装了安全过滤器,既作为常规过滤器,又作为安全过滤器:
@Component
public class FilterPrinter implements CommandLineRunner {
@Autowired
List<SecurityFilterChain> securityFilterChains;
@Override
public void run(String... args) throws Exception {
for (int i = 0; i < securityFilterChains.size(); i++) {
SecurityFilterChain securityFilterChain = securityFilterChains.get(i);
System.out.println("security chain #" + (i + 1) + " filters:");
System.out.println("-----");
List<Filter> filters = securityFilterChain.getFilters();
filters.forEach(filter
-> System.out.println("- " + filter.getClass().getSimpleName())
);
}
}
@Bean
public CommandLineRunner cmdLineRunner(ApplicationContext context) {
return args -> {
ServletContextInitializerBeans scib = new ServletContextInitializerBeans(context,
FilterRegistrationBean.class, DelegatingFilterProxyRegistrationBean.class);
System.out.println("request filters:");
System.out.println("----");
scib.iterator().forEachRemaining(s -> {
System.out.println("- " + s);
});
};
}
}