在使用springSecurity过滤器的过程中,由于需要自定义一个过滤器处理数据问题。代码如下:
过滤器定义:
public class AuthRequestParamFiler extends GenericFilterBean {
private static final CoreLogger LOGGER = CoreLoggerFactory.getLogger(AuthRequestParamFiler.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String path = httpRequest.getServletPath();
if(path.equals("/oauth/token")) {
LOGGER.info("AuthRequestFiler 过滤器, path:{}", path);
Map<String, String> requestMap = HttpUtil.getRequestPostMap(httpRequest);
AuthParamRequestWrapper contentCachingRequestWrapper = new AuthParamRequestWrapper(httpRequest, requestMap);
chain.doFilter(contentCachingRequestWrapper, response);
} else {
chain.doFilter(request, response);
}
}
}
过滤器注册:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthWebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthUserDetailsService authUserDetailsService;
/**
* 对请求进行鉴权的配置
* https://zhuanlan.zhihu.com/p/181156708
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(authUserDetailsService);
http.authorizeRequests()
//.antMatchers().permitAll()
.anyRequest().authenticated()
.and()
// 暂时关闭CSRF校验,允许get请求登出
.csrf().disable()
.addFilterBefore(new AuthRequestParamFiler(), UsernamePasswordAuthenticationFilter.class);
}
}
但是在执行中却没有执行该过滤器。
首先排查代码问题。通过debug可以看出,服务一共构造了两个WebSecurityConfigurerAdapter类,每一个类都有自己的DefaultSecurityFilterChain调用链。
第一个:
第二个:
看得出来,我的AuthRequestParamFiler已经注册到了这个过滤器链路里面。但是,在实际执行中却没有执行。
但是我的代码能真长的返回。由此可以看出,是没有执行到这个拦截器就已经返回了。
通过查询FilterChainProxy的代码我们可以看到在获取调用链的时候,只要匹配到一个就直接返回了。这就有可能会导致如果我的自定义拦截器排在了其他拦截器的后面,会先返回其他的拦截器。
public class FilterChainProxy extends GenericFilterBean {
private List<Filter> getFilters(HttpServletRequest request) {
for (SecurityFilterChain chain : filterChains) {
if (chain.matches(request)) {
return chain.getFilters();
}
}
return null;
}
}
在spring的网站中也有提到:
所以应该是我的过滤器排在系统默认的拦截器之后的原因导致的。这个排序是在WebSecurityConfiguration中实现的。AutowiredWebSecurityConfigurersIgnoreParents类获取了所有定义的WebSecurityConfigurer继承类。setFilterChainProxySecurityConfigurer()方法对传入的参数进行了排序。排序方式是按照@Ordered配置的大小来决定的。
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
private Boolean debugEnabled;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
private ClassLoader beanClassLoader;
@Autowired(required = false)
private ObjectPostProcessor<Object> objectObjectPostProcessor;
@Bean
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
ConfigurableListableBeanFactory beanFactory) {
//这个方法里面会获取所有的 WebSecurityConfigurer 类
return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
}
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
webSecurity = objectPostProcessor
.postProcess(new WebSecurity(objectPostProcessor));
if (debugEnabled != null) {
webSecurity.debug(debugEnabled);
}
//这里进行了排序
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
if (previousOrder != null && previousOrder.equals(order)) {
throw new IllegalStateException(
"@Order on WebSecurityConfigurers must be unique. Order of "
+ order + " was already used on " + previousConfig + ", so it cannot be used on "
+ config + " too.");
}
previousOrder = order;
previousConfig = config;
}
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
webSecurity.apply(webSecurityConfigurer);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
}
通过查看另外一个WebSecurityConfigurer的继承类AuthorizationServerSecurityConfiguration
@Configuration
@Order(0)
@Import({ ClientDetailsServiceConfiguration.class, AuthorizationServerEndpointsConfiguration.class })
public class AuthorizationServerSecurityConfiguration extends WebSecurityConfigurerAdapter {
......
}
可以看出这个的配置的序号是0。所以我们自定义的AuthWebServiceSecurityConfig的序号要比0小。
注意:一旦做了这个配置就会导致原来的oauth2的Filer无法使用,进而导致无法使用oauth2的授权接口。