Java-Security(二):如何初始化springSecurityFilterChain(FilterChainProxy)

上一篇文章中,接觸了Spring Security並寫了一個簡單的實例,初次接觸畢竟我們對它還不是特別熟悉。我比較好奇的問題包含兩處:

1)配置在web.xml配置的springSecurityFilterChain是如何被加載?
2)配置在applicationContext-security.xml中的標籤csrf、form-login、logout是如何被解析的呢?

1)配置在web.xml配置的springSecurityFilterChain是如何被加載?

springmvc+spring security項目中web.xml配置了springSecurityFilterChain

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <!-- 默認是false -->
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

org.springframework.web.filter.DelegatingFilterProxy 只是和其他filter一樣,是一個javax.servlet.Filter,它將在web servlet系統啓動時:先調用listener(pre )->filter(pre doFilter)->servlet([spring mvc]DispatcherServlet)->filter(after doFilter)->listener(after )

因此項目啓動時,會執行DelegatingFilterProxy#doFilter方法

     @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        // Lazily initialize the delegate if necessary.
        Filter delegateToUse = this.delegate;
        if (delegateToUse == null) {
            synchronized (this.delegateMonitor) {
                delegateToUse = this.delegate;
                if (delegateToUse == null) {
                    WebApplicationContext wac = findWebApplicationContext();
                    if (wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: " +
                                "no ContextLoaderListener or DispatcherServlet registered?");
                    }
                    delegateToUse = initDelegate(wac);
                }
                this.delegate = delegateToUse;
            }
        }

        // Let the delegate perform the actual doFilter operation.
        invokeDelegate(delegateToUse, request, response, filterChain);
    }

上邊filter執行主要負責兩個事情:

1)執行initDelegate(wac)方法,初始化delegate對象

因爲 DelegatingFilterProxy 類繼承於抽象類(springframework的)GenericFilterBean,會在初始化bean時,調用 DelegatingFilterProxy#initFilterBean()

GenericFilterBean的定義:

public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware,
        EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean {
    // ...

    @Override
    public void afterPropertiesSet() throws ServletException {
        initFilterBean();
    }

    // ...

    protected void initFilterBean() throws ServletException {
    }

    // ...
}

因爲GenericFilterBean實現InitializingBean接口,因此項目啓動時,spring容器加載bean後,會執行afterPropertiesSet()方法,之後會調用initFilterBean()方法。

DelegatingFilterProxy#initFilterBean()的定義:

public class DelegatingFilterProxy extends GenericFilterBean {
    // ...

    @Nullable
    private volatile Filter delegate;

    // ...

    @Override
    protected void initFilterBean() throws ServletException {
        synchronized (this.delegateMonitor) {
            if (this.delegate == null) {
                // If no target bean name specified, use filter name.
                if (this.targetBeanName == null) {
                    this.targetBeanName = getFilterName();
                }
                // Fetch Spring root application context and initialize the delegate early,
                // if possible. If the root application context will be started after this
                // filter proxy, we'll have to resort to lazy initialization.
                WebApplicationContext wac = findWebApplicationContext();
                if (wac != null) {
                    this.delegate = initDelegate(wac);
                }
            }
        }
    }

    // ...

    protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        String targetBeanName = getTargetBeanName();
        Assert.state(targetBeanName != null, "No target bean name set");
        Filter delegate = wac.getBean(targetBeanName, Filter.class);
        if (isTargetFilterLifecycle()) {
            delegate.init(getFilterConfig());
        }
        return delegate;
    }

    // ...
}

當然,無論targetFilterLifecycle是true還是false,都不會影響springSecurityFilterChain的初始化(無論true還是false,以下截圖的結果都一樣)。

從上圖我們能得出的結論:

1)上邊targetBeanName是springSecurityFilterChain,通過調用wac.getBean(targetBeanName, Filter.class);從spring容器中獲取到對象的類:org.springframework.security.web.FilterChainProxy;

2)‘org.springframework.security.web.FilterChainProxy#filterChains’與‘applicationContext-shiro.xml中的<http/>標籤對應’;

3)‘filterChains的個數’與‘applicationContext-shiro.xml中的<http/>標籤個數一致’,也就是說:在applicationContext-shiro.xml中配置了幾個<http/>標籤,那麼,‘org.springframework.security.web.FilterChainProxy#filterChains’就對應幾個 ‘DefaultSecurityFilterChain’ 對象元素。

4)這個 springSecurityFilterChain 的bean是如何初始化,和什麼時候放入spring容器的呢?在ContextLoaderListener加載applicationContext-security.xml時,解析配置文件時將springSecurityFilterChain初始化放入容器的,這個問題後邊會詳細介紹。

2)執行invokeDelegate(...)方法

實際上就是執行FilterChainProxy#doFilter(...)方法

    protected void invokeDelegate(
            Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        delegate.doFilter(request, response, filterChain);
    }

2)配置在applicationContext-security.xml中的標籤csrf、form-login、logout是如何被解析的呢?

applicationContext-security.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
    <!--
    從Spring Security 3.1開始,可以使用多個http元素爲不同的請求模式定義單獨的安全過濾器鏈配置。
    -->
    <security:http pattern="/css/**" security="none"/>

    <security:http auto-config="true" use-expressions="false">
        <security:csrf disabled="false"/>
        <security:intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <security:intercept-url pattern="/index" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <security:intercept-url pattern="/**" access="ROLE_USER"/>

        <security:form-login default-target-url="/index" />
        <security:logout delete-cookies="JSESSIONID" logout-success-url="/login" logout-url="/logout" />

    </security:http>

    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <!-- Password is prefixed with {noop} to indicate to DelegatingPasswordEncoder that
                NoOpPasswordEncoder should be used. This is not safe for production, but makes reading
                in samples easier. Normally passwords should be hashed using BCrypt
                -->
                <security:user name="admin" password="{noop}adminpwd" authorities="ROLE_USER, ROLE_ADMIN"/>
                <security:user name="user" password="{noop}userpwd" authorities="ROLE_USER"/>
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>

</beans>

上邊的配置文件是比較簡單的spring security配置文件了,在 springmvc(web.xml非註解方式)+spring security 項目中,我們需要清楚一件事:就是web.xml中配置的內容的執行先後順序。

web.xml配置內容如下:

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <welcome-file-list>
        <welcome-file>/index</welcome-file>
    </welcome-file-list>

    <!--加載dao/service/一些共享組件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:applicationContext-base.xml,
            classpath:applicationContext-security.xml
        </param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <!-- 默認是false -->
            <param-value>false</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>multipartFilter</filter-name>
        <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
        <init-param>
            <param-name>multipartResolverBeanName</param-name>
            <param-value>multipartResolver</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>multipartFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
        <init-param>
            <param-name>methodParam</param-name>
            <param-value>_method</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--加載springmvc controller viewsolver 等-->
    <servlet>
        <servlet-name>spring-security-01</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-security-01-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring-security-01</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
配置文件中指定的
View Code

有兩個spring application context初始化的地方:

1)ContextLoaderListener加載applicationContext-base.xml、applicationContext-security.xml,初始化parent application context;
2)DispatcherServlet加載spring-security-01-servlet.xml,初始化child application context。

注意:

1)web.xml中配置內容加載順序:

-》listener[pre] -》filter[pre] -》springmvc內部處理 -》filter[after] -》listener[after];

2)ContextLoaderListener 加載 applicationContext-security.xml 時,需要先根據標籤解析器(SecurityNamespaceHandler)解析xml中配置http、csrf、form-login、logout等標籤:

在spring-security項目config模塊的src/main/resources/META-INF/spring.handlers文件中配合這這樣一行代碼:

http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler

從這裏可以看出來spring security的標籤解析器是 org.springframework.security.config.SecurityNamespaceHandler 來處理。

SecurityNamespaceHandler該類接口是:NamespaceHandler

public interface NamespaceHandler {
    void init();

    @Nullable
    BeanDefinition parse(Element element, ParserContext parserContext);

    @Nullable
    BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
}

該接口定義了三個方法:

init方法:用於自定義標籤的初始化
parse方法:用於解析標籤
decorate方法:用於裝飾。

SecurityNamespaceHandler類

在spring-security項目中,加載applicationContext-security.xml中處理xml中配置http、csrf、form-login、logout等(所有xml配置security標籤,具體所有標籤定義:參考org.springframework.security.config.Elements.java),在處理xml這些標籤的最終目的是:
解析xml中配置的bean,並將它們加載到spring-framework上下文,供spring-security、spring-mvc項目使用。

其中在org.springframework.security.config.SecurityNamespaceHandler#init方法完成了標籤解析類註冊的工作:

    public void init() {
        loadParsers();
    }

    private void loadParsers() {
        // Parsers
        parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
        parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
        parsers.put(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());
        parsers.put(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());
        parsers.put(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());
        parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
        parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
        parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
        parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE, new MethodSecurityMetadataSourceBeanDefinitionParser());

        // Only load the web-namespace parsers if the web classes are available
        if (ClassUtils.isPresent(FILTER_CHAIN_PROXY_CLASSNAME, getClass().getClassLoader())) {
            parsers.put(Elements.DEBUG, new DebugBeanDefinitionParser());
            parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
            parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
            parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
            parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
            filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
        }

        if (ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
            parsers.put(Elements.WEBSOCKET_MESSAGE_BROKER, new WebSocketMessageBrokerSecurityBeanDefinitionParser());
        }
    }

從上邊代碼可以看出:

<http/>標籤的解析類註冊代碼爲:parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
<authentication-manager/>標籤的解析類註冊代碼爲:parsers.put(Elements.AUTHENTICATION_MANAGER,new AuthenticationManagerBeanDefinitionParser());
<authentication-provider/>標籤的解析類註冊代碼爲:parsers.put(Elements.AUTHENTICATION_PROVIDER,new AuthenticationProviderBeanDefinitionParser())。

HttpSecurityBeanDefinitionParser類

HttpSecurityBeanDefinitionParser的parse方法代碼:

    @Override
    public BeanDefinition parse(Element element, ParserContext pc) {
        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(
                element.getTagName(), pc.extractSource(element));
        pc.pushContainingComponent(compositeDef);

        registerFilterChainProxyIfNecessary(pc, pc.extractSource(element));

        // Obtain the filter chains and add the new chain to it 
        // 這裏FILTER_CHAINS字符串爲:org.springframework.security.filterChains
        BeanDefinition listFactoryBean = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAINS);
        // 其中sourceList是從spring-security.xsd 文件中讀取的:
        List<BeanReference> filterChains = (List<BeanReference>) listFactoryBean.getPropertyValues().getPropertyValue("sourceList").getValue();

        filterChains.add(createFilterChain(element, pc));

        pc.popAndRegisterContainingComponent();
        return null;
    }

其中 registerFilterChainProxyIfNecessary()實現代碼如下:

    static void registerFilterChainProxyIfNecessary(ParserContext pc, Object source) {
        if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
            return;
        }
        // Not already registered, so register the list of filter chains and the
        // FilterChainProxy
        BeanDefinition listFactoryBean = new RootBeanDefinition(ListFactoryBean.class);
        listFactoryBean.getPropertyValues().add("sourceList", new ManagedList());
        pc.registerBeanComponent(new BeanComponentDefinition(listFactoryBean, BeanIds.FILTER_CHAINS));

        BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
        fcpBldr.getRawBeanDefinition().setSource(source);
        fcpBldr.addConstructorArgReference(BeanIds.FILTER_CHAINS);
        fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(DefaultFilterChainValidator.class));
        BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
        pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
        pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
    }

備註:

1)FILTER_CHAIN_PROXY 就是 org.springframework.security.filterChainProxy

2)SPRING_SECURITY_FILTER_CHAIN 就是 springSecurityFilterChain

3)這段代碼就是註冊bean定義 FilterChainProxy 註冊的地方,將bean名稱定義爲:org.springframework.security.filterChainProxy 和 springSecurityChainFilter(別名)

其中,createFilterChain方法

    /**
     * Creates the {@code SecurityFilterChain} bean from an &lt;http&gt; element.
     */
    private BeanReference createFilterChain(Element element, ParserContext pc) {
        boolean secured = !OPT_SECURITY_NONE.equals(element.getAttribute(ATT_SECURED));

        if (!secured) {
            if (!StringUtils.hasText(element.getAttribute(ATT_PATH_PATTERN))
                    && !StringUtils.hasText(ATT_REQUEST_MATCHER_REF)) {
                pc.getReaderContext().error(
                        "The '" + ATT_SECURED
                                + "' attribute must be used in combination with"
                                + " the '" + ATT_PATH_PATTERN + "' or '"
                                + ATT_REQUEST_MATCHER_REF + "' attributes.",
                        pc.extractSource(element));
            }

            for (int n = 0; n < element.getChildNodes().getLength(); n++) {
                if (element.getChildNodes().item(n) instanceof Element) {
                    pc.getReaderContext().error(
                            "If you are using <http> to define an unsecured pattern, "
                                    + "it cannot contain child elements.",
                            pc.extractSource(element));
                }
            }

            return createSecurityFilterChainBean(element, pc, Collections.emptyList());
        }

        final BeanReference portMapper = createPortMapper(element, pc);
        final BeanReference portResolver = createPortResolver(portMapper, pc);

        ManagedList<BeanReference> authenticationProviders = new ManagedList<>();
        BeanReference authenticationManager = createAuthenticationManager(element, pc,
                authenticationProviders);

        boolean forceAutoConfig = isDefaultHttpConfig(element);
        HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element,
                forceAutoConfig, pc, portMapper, portResolver, authenticationManager);

        AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element,
                forceAutoConfig, pc, httpBldr.getSessionCreationPolicy(),
                httpBldr.getRequestCache(), authenticationManager,
                httpBldr.getSessionStrategy(), portMapper, portResolver,
                httpBldr.getCsrfLogoutHandler());

        httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
        httpBldr.setEntryPoint(authBldr.getEntryPointBean());
        httpBldr.setAccessDeniedHandler(authBldr.getAccessDeniedHandlerBean());

        authenticationProviders.addAll(authBldr.getProviders());

        List<OrderDecorator> unorderedFilterChain = new ArrayList<>();

        unorderedFilterChain.addAll(httpBldr.getFilters());
        unorderedFilterChain.addAll(authBldr.getFilters());
        unorderedFilterChain.addAll(buildCustomFilterList(element, pc));

        unorderedFilterChain.sort(new OrderComparator());
        checkFilterChainOrder(unorderedFilterChain, pc, pc.extractSource(element));

        // The list of filter beans
        List<BeanMetadataElement> filterChain = new ManagedList<>();

        for (OrderDecorator od : unorderedFilterChain) {
            filterChain.add(od.bean);
        }

        return createSecurityFilterChainBean(element, pc, filterChain);
    }

此時HttpSecurityBeanDefinitionParser的parse方法,filterChains.add(createFilterChain(element,pc))就是註冊各個filter bean定義的代碼,通過斷點調試可以發現。

1)其中 forceAutoConfig 就是讀取<http auto-config='true'...></http>,如果auto-config=true,那麼在 HttpConfigurationBuilder、AuthenticationConfigBuilder 中會自動加載所有security filter的bean定義。

其中 AuthenticationConfigBuilder 中創建filter BeanDefinition代碼:

        createAnonymousFilter();
        createRememberMeFilter(authenticationManager);
        createBasicFilter(authenticationManager);
        createFormLoginFilter(sessionStrategy, authenticationManager);
        createOpenIDLoginFilter(sessionStrategy, authenticationManager);
        createX509Filter(authenticationManager);
        createJeeFilter(authenticationManager);
        createLogoutFilter();
        createLoginPageFilterIfNeeded();
        createUserDetailsServiceFactory();
        createExceptionTranslationFilter();

HttpConfigurationBuilder 中創建filter BeanDefinition代碼:

        createCsrfFilter();
        createSecurityContextPersistenceFilter();
        createSessionManagementFilters();
        createWebAsyncManagerFilter();
        createRequestCacheFilter();
        createServletApiFilter(authenticationManager);
        createJaasApiFilter();
        createChannelProcessingFilter();
        createFilterSecurityInterceptor(authenticationManager);
        createAddHeadersFilter();
        createCorsFilter();

2)如果在 <http security="none" ... ></http> 將會特殊處理,需要注意。

跟蹤spring applicationContext中加載bean

從上圖解析到的bean就是加載applicationContext-*.xml的配置內容的bean:
1)加載applicationContext-base.xml的相關bean定義:
其中前邊的

loginController
indexController
org.springframework.context.annotation.internalConfigurationAnnotationProcessor // 處理 @Configuration 註解
org.springframework.context.annotation.internalAutowiredAnnotationProcessor // 處理 @Autowired、@Value、@Inject 註解
org.springframework.context.annotation.internalCommonAnnotationProcessor // 處理 @PostConstruct、@PreDestroy、@Resource、@WebServiceRef
org.springframework.context.event.internalEventListenerProcessor    // 處理 @EventListener 註解
org.springframework.context.event.internalEventListenerFactory
multipartResolver // 定義的文件上傳解析器 bean

這些都是在加載applicationContext-base.xml時,加載的相關bean定義。
上邊org.springframework.context的bean定義在 spring-context-5.2.0.RELEASE-sources.jar!/org/springframework/context/annotation/AnnotationConfigUtils.java中。

其中定義的各個bean的對應的BeanPostProcessor類:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor 對應的類 org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor 對應的類 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor 對應的類 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
org.springframework.context.annotation.internalPersistenceAnnotationProcessor 對應的類 org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
org.springframework.context.event.internalEventListenerProcessor 對應的類 org.springframework.context.event.EventListenerMethodProcessor
org.springframework.context.event.internalEventListenerFactory 對應的類 org.springframework.context.event.DefaultEventListenerFactory

2)加載applicationContext-security.xml的相關bean定義:

8 = "org.springframework.security.filterChains"
9 = "org.springframework.security.filterChainProxy"
10 = "org.springframework.security.web.DefaultSecurityFilterChain#0"
11 = "org.springframework.security.web.PortMapperImpl#0"
12 = "org.springframework.security.web.PortResolverImpl#0"
13 = "org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0"
14 = "org.springframework.security.authentication.ProviderManager#0"
15 = "requestDataValueProcessor"
16 = "org.springframework.security.web.csrf.LazyCsrfTokenRepository#0"
17 = "org.springframework.security.web.context.HttpSessionSecurityContextRepository#0"
18 = "org.springframework.security.core.session.SessionRegistryImpl#0"
19 = "org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy#0"
20 = "org.springframework.security.web.savedrequest.HttpSessionRequestCache#0"
21 = "org.springframework.security.config.http.HttpConfigurationBuilder$SecurityContextHolderAwareRequestFilterBeanFactory#0"
22 = "org.springframework.security.config.http.HttpConfigurationBuilder$RoleVoterBeanFactory#0"
23 = "org.springframework.security.access.vote.AffirmativeBased#0"
24 = "org.springframework.security.web.access.intercept.FilterSecurityInterceptor#0"
25 = "org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator#0"
26 = "org.springframework.security.authentication.AnonymousAuthenticationProvider#0"
27 = "org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint#0"
28 = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0"
29 = "org.springframework.security.userDetailsServiceFactory"
30 = "org.springframework.security.web.DefaultSecurityFilterChain#1"
31 = "bCryptPasswordEncoder"
32 = "org.springframework.security.provisioning.InMemoryUserDetailsManager#0"
33 = "org.springframework.security.authentication.dao.DaoAuthenticationProvider#0"
34 = "org.springframework.security.authentication.DefaultAuthenticationEventPublisher#0"
35 = "org.springframework.security.authenticationManager"

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章