一、spring security过滤器默认配置
WebSecurityConfigurerAdapter.init()
WebSecurityConfigurerAdapter.getHttp()
new HttpSecurity()
new FilterComparator()
按优先级顺序放入,前面的优先级比后面的高,关键的filter
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(ChannelProcessingFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
put(WebAsyncManagerIntegrationFilter.class, order.next());
put(SecurityContextPersistenceFilter.class, order.next());
put(HeaderWriterFilter.class, order.next());
put(CorsFilter.class, order.next());
put(CsrfFilter.class, order.next());
put(LogoutFilter.class, order.next());
filterToOrder.put( "org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter", order.next());
put(X509AuthenticationFilter.class, order.next());
put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
order.next());
filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
order.next());
put(UsernamePasswordAuthenticationFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
put(DefaultLoginPageGeneratingFilter.class, order.next());
put(DefaultLogoutPageGeneratingFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
put(DigestAuthenticationFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter", order.next());
put(BasicAuthenticationFilter.class, order.next());
put(RequestCacheAwareFilter.class, order.next());
put(SecurityContextHolderAwareRequestFilter.class, order.next());
put(JaasApiIntegrationFilter.class, order.next());
put(RememberMeAuthenticationFilter.class, order.next());
put(AnonymousAuthenticationFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
order.next());
put(SessionManagementFilter.class, order.next());
put(ExceptionTranslationFilter.class, order.next());
put(FilterSecurityInterceptor.class, order.next());
put(SwitchUserFilter.class, order.next());
二、springsecurity过滤器链springSecurityFilterChain通过代理创建(懒加载)
1、oauth2认证中心
查看容器中的关于springsecurity需要的filter(springSecurityFilterChain),需要跟踪tomcat支持包下的ApplicationFilterFactory类,查看返回的过滤器链对象filterChain,ApplicationFilterFactory.createFilterChain(ServletRequest request,Wrapper wrapper, Servlet servlet),也可以查看DelegatingFilterProxy.initDelegate(WebApplicationContext wac),这个方法是在执行DelegatingFilterProxy的doFilter方法时才会执行,达到懒加载delegate的目的。
适配后的过滤器链
token相关(/oauth/token,/oauth/token_key,/oauth/check_token)的springSecurityFilterChain过滤器链(按优先级顺序)
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
ClientCredentialsTokenEndpointFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
anyRequest相关springSecurityFilterChain的过滤器链
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
2、oauth2的SSO客户端(@EnableOAuth2Sso)过滤器如下:
客户端注解@EnableOAuth2Client引入的过滤器
OAuth2ClientContextFilter
客户端的springSecurityFilterChain过滤器链
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
OAuth2ClientAuthenticationProcessingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
三、springsecurity过滤器链所处容器中过滤器链的位置如下图所示
四、请求与过滤器链
1、springSecurityFilterChain
初始化过滤器:启动tomcat容器时,ServletContextInitializerBeans.addAdaptableBeans会从beanFactory将实现javax.servlet.Filter接口相关的bean(含springSecurityFilterChain类型为DelegatingFilterProxyRegistrationBean)加载到initializers
再执行ServletContextInitializerBeans.onStartup(ServletContext servletContext)将执行springSecurityFilterChain.getFilter()获取到DelegatingFilterProxy的实例并添加到容器ServletContext(即ApplicationContext,真正存入StandardContext,filter以FilterDef类型存储)中。
2、处理请求
1)调用tomcat的类StandardWrapperValve的invoke方法,获取整体的过滤器链ApplicationFilterChain并执行。
获取整体的过滤器链ApplicationFilterFactory.createFilterChain从StandardContext中获取适合的过滤器配置(ApplicationFilterConfig)添加到过滤器链中。
public final void invoke(Request request, Response response)
throws IOException, ServletException {
....
// Create the filter chain for this request
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
Container container = this.container;
try {
....
filterChain.doFilter(request.getRequest(),
response.getResponse());
....
} catch (Exception e) {
.....
} finally {
// Release the filter chain (if any) for this request
if (filterChain != null) {
filterChain.release();
}
....
}
ApplicationFilterChain过滤器链执行方法doFilter,内部执行internalDoFilter方法
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];//获取过滤器链中下一个过滤器配置
try {
Filter filter = filterConfig.getFilter();//从配置中得到过滤器
.....
filter.doFilter(request, response, this);//过滤器执行时,需要将当前的过滤器链作为参数传入,以便在过滤器内部执行过滤器链的doFilter方法,调用下一个过滤器,实现过滤器的链式调用
}
}
....
}
2)执行springsecurity的过滤器链springSecurityFilterChain
当执行到springSecurityFilterChain,再执行DelegatingFilterProxy.doFilter、initDelegate完成对FilterChainProxy(delegate真正的springSecurity过滤器链)的实例的创建, 再执行DelegatingFilterProxy.invokeDelegate方法,调用FilterChainProxy.doFilter执行doFilterInternal方法创建VirtualFilterChain(这个就是springsecurity真正的过滤器链,包含原始的过滤器链ApplicationFilterChain和springsecurity的过滤器列表)并执行它的doFilter来开始执行springsecurity的过滤器链,内部先执行springsecurity的过滤器链,最后再回到原始的过滤器链originalChain(ApplicationFilterChain),继续执行后续的过滤器。
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if (currentPosition == size) {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " reached end of additional filter chain; proceeding with original chain");
}
// Deactivate path stripping as we exit the security filter chain
this.firewalledRequest.reset();
originalChain.doFilter(request, response);
}
else {
currentPosition++;
Filter nextFilter = additionalFilters.get(currentPosition - 1);
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " at position " + currentPosition + " of " + size
+ " in additional filter chain; firing Filter: '"
+ nextFilter.getClass().getSimpleName() + "'");
}
nextFilter.doFilter(request, response, this);
}
}
3)过滤器链执行流程