zoukankan      html  css  js  c++  java
  • 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"
  • 相关阅读:
    Bzoj3339 Rmq Problem
    Bzoj3509 [CodeChef] COUNTARI
    浅析python日志重复输出问题
    mysql练习题
    python学习之思维导图
    python面向对象编程练习
    Python常见下划线
    内置方法
    类的绑定方法与非绑定方法
    封装
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/12194142.html
Copyright © 2011-2022 走看看