我试图在弹簧过滤器链中插入(在第一个位置)一个简单的自定义 Cors 过滤器。
如果我这样做
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
它完美地工作 我可以通过在 Spring 的 ServletHandler.java 中放置一个断点来验证它,那里有行
chain=getFilterChain(baseRequest, target, servlet_holder);
我只是想知道我是否希望 not 使用
@Componenent and @Order
而不是在应用程序上下文中定义 Filter bean。
如何设置过滤器的顺序?
参见示例: 在你的班级 ServletInitializer:
@Bean
public FilterRegistrationBean requestLogFilter() {
final FilterRegistrationBean reg = new FilterRegistrationBean(createRequestLogFilter());
reg.addUrlPatterns("/*");
reg.setOrder(1); //defines filter execution order
return reg;
}
@Bean
public RequestLogFilter createRequestLogFilter(){
return new RequestLogFilter();
}
我的过滤器的名称是“requestLogFilter”
警告:不要在 Filter 类中使用 @Component 注解。
对于 corsFilter,通常需要将此过滤器的加载顺序设置在 springSecurityFilterChain 和其他过滤器(例如 spring boot 中的 errorPageFilter)之前加载到链的最开头。否则 CORS 支持将被破坏,并且不会引入所需的标头。这可以通过以下事情来完成:
@Configuration
public class MyConfiguration {
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Integer.MIN_VALUE);
return bean;
}
}
bean.setOrder(Integer.MIN_VALUE) 将确保这是第一个加载的过滤器。即使还有其他过滤器,例如 order 设置为 Integer.MIN_VALUE(-2147483648) 的 errorPage 过滤器。
另一种选择是让您的过滤器实现
org.springframework.core.Ordered
,如果您使用的是 spring webflux(它没有FilterRegistrationBean
),这是唯一的选择:
public class CorsFilter implements Filter, Ordered {
//...
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE
}
}
或者您甚至可以将其设为过滤器中的变量。
@Configuration
@ComponentScan
@ConfigurationPropertiesScan
class CommonConfig {
@Autowired
lateinit var chains: List<SecurityFilterChain>
@Autowired
lateinit var myCustomFilter: MyCustomFilter
@PostConstruct
fun post() {
chains.forEach {
for (i in it.filters.indices){
if (it.filters[i] is LogoutFilter) {
it.filters.add(i + 1, myCustomFilter)
}
}
}
}
}
假设我们有以下链:
@Bean
@Throws(Exception::class)
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http.authorizeRequests()
.antMatchers(HttpMethod.POST, "/first", "/second")
.authenticated()
.anyRequest()
.permitAll()
.and()
.httpBasic()
.authenticationEntryPoint(auditAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().formLogin().disable()
.csrf().disable()
.cors().configurationSource(corsConfigurationSource())
return http.build()
}
我们想在一些特定过滤器之间的这个链中添加以下过滤器:
@Component
class MyCustomFilter : OncePerRequestFilter() {
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
//some work: adding headers, working with authentication or something else
filterChain.doFilter(request, response)
}
}
这里有几种方法可以将我们的过滤器添加到链中:
@Component
@Order(5)
class MyCustomFilter : OncePerRequestFilter()
注意:
Ordered.LOWEST_PRECEDENCE
- 您的过滤器将是链中的最后一个。Ordered.LOWEST_PRECEDENCE
和 Ordered.HIGHEST_PRECEDENCE
不适合您的情况,因为:
Ordered.HIGHEST_PRECEDENCE
过滤器SecurityContextPersistenceFilter
将在您之后执行
过滤器将清除 SecurityContext,即使您的过滤器将 Authentication 对象添加到 SecurityContextOrdered.LOWEST_PRECEDENCE
的情况下,您的过滤器根本不会被调用:AnonymousAuthenticationFilter 会将 Authentication 对象设置为
匿名,您将在连锁店调用您的过滤器之前收到 401 或 403 响应FilterChainProxy
和doFilter(ServletRequest request, ServletResponse response)
方法,得到this.additionalFilters
。例如,5
。
但这不是确定顺序的最佳方法 @Bean
@Throws(Exception::class)
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http.authorizeRequests()
...
.addFilterBefore(MyCustomFulter(), BasicAuthenticationFilter::class.java)
...
return http.build()
}
在我的例子中,.addFilterBefore() 是不可能的,因为 过滤器是从启动器添加的。我的启动器需要添加一个过滤器 到 LogoutFilter 之后的每个链。因为可以有多个链 一个上下文,我为每个添加一个过滤器。因此,将我的启动器添加到应用程序时 ,过滤器添加到需要的地方,无需任何额外配置:
@Configuration
@ComponentScan
@ConfigurationPropertiesScan
class CommonConfig {
@Autowired
lateinit var chains: List<SecurityFilterChain>
@Autowired
lateinit var myCustomFilter: MyCustomFilter
@PostConstruct
fun post() {
chains.forEach {
for (i in it.filters.indices){
if (it.filters[i] is LogoutFilter) {
it.filters.add(i + 1, myCustomFilter)
}
}
}
}
}