如何确保SecurityFilterChain中的安全过滤器先于ProfileSynchronizationFilter执行?
我有一个通过SecurityFilterChain注册的BearerTokenAuthenticationFilter(对应代码中的jwtAuthenticationFilter),另外还有一个通过FilterRegistrationBean注册的ProfileSynchronizationFilter。目前ProfileSynchronizationFilter会先于BearerTokenAuthenticationFilter执行,但实际需求是让ProfileSynchronizationFilter在认证过滤器之后运行。
我了解到SecurityFilterChain中的过滤器由DelegatingFilterProxy代理执行,推测需要调整DelegatingFilterProxy与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; }
要实现BearerTokenAuthenticationFilter先执行,有两种可靠的实现方式:
方案一:将自定义过滤器加入SecurityFilterChain内部(推荐)
这种方式能精准控制过滤器在Security链中的位置,避免和Servlet容器的其他过滤器顺序冲突。
- 修改
SecurityFilterChain配置,在认证过滤器之后添加ProfileSynchronizationFilter:
@Bean @Order(2) public SecurityFilterChain filterChain(HttpSecurity http, ProfileSynchronizationFilter profileSynchronizationFilter) 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) // 明确指定在BearerTokenAuthenticationFilter之后执行 .addFilterAfter(profileSynchronizationFilter, BearerTokenAuthenticationFilter.class) .anonymous() .disable(); return http.build(); }
- 删除原来的
FilterRegistrationBean配置,避免过滤器被重复注册:
// 移除该Bean定义 // @Bean // public FilterRegistrationBean registerProfileSynchronizationFilter(ProfileSynchronizationFilter profileSynchronizationFilter) { // FilterRegistrationBean reg = new FilterRegistrationBean(profileSynchronizationFilter); // reg.setOrder(6); // return reg; // }
方案二:调整自定义过滤器的Order值
如果必须保留FilterRegistrationBean的注册方式,需要确保自定义过滤器的Order值大于Spring Security核心过滤器FilterChainProxy的Order值(默认是-100)。因为Servlet过滤器的Order值越小,执行优先级越高,所以设置更大的Order值就能让它在Security过滤器之后运行。
修改FilterRegistrationBean配置:
@Bean public FilterRegistrationBean registerProfileSynchronizationFilter(ProfileSynchronizationFilter profileSynchronizationFilter) { FilterRegistrationBean reg = new FilterRegistrationBean(profileSynchronizationFilter); // 设置Order值大于-100,确保在Security过滤器之后执行 reg.setOrder(0); // 可选:限制过滤器仅对需要认证的资源生效,和Security配置保持一致 reg.addUrlPatterns(listOfSecuredResources.toArray(new String[0])); return reg; }
注意:如果项目中修改了Spring Security的默认Filter Order(比如通过security.filter.order配置项),需要将自定义过滤器的Order值设置为比该配置值更大的数。
内容的提问来源于stack exchange,提问作者sbrattla

