Bootstrap

spring security filter

一、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)过滤器链执行流程

;