Spring Security3源码分析-FilterChainProxy初始化

spring security的教程网上很多: 
http://lengyun3566.iteye.com/category/153689  
http://wenku.baidu.com/view/b0c0dc0b79563c1ec5da7179.html  

以上教程足够应付在实际项目中使用spring security这一安全框架了。如果想深入研究下,网上的资料就很少了,比如: 
http://www.blogjava.net/SpartaYew/archive/2011/05/19/spingsecurity3.html  
http://www.blogjava.net/youxia/archive/2008/12/07/244883.html  
http://www.cnblogs.com/hzhuxin/archive/2011/12/19/2293730.html  

但还是没有从filter配置开始进行一步一步分析。 
带着很多疑问,逐步拨开spring security3的面纱 
spring security在web.xml中的配置为 
Xml代码   收藏代码
  1. <filter>  
  2.     <filter-name>springSecurityFilterChain</filter-name>  
  3.     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  4. </filter>  
  5. <filter-mapping>  
  6.     <filter-name>springSecurityFilterChain</filter-name>  
  7.     <url-pattern>/*</url-pattern>  
  8. </filter-mapping>  

一看就知道,这是spring的类,这个类位于org.springframework.web-3.0.1.RELEASE.jar这个jar下面,说明这个类本身是和springSecurity无关。DelegatingFilterProxy类继承于抽象类GenericFilterBean,间接地实现了javax.servlet.Filter接口。细节方面就不一一讲述了。看doFilter方法 
Java代码   收藏代码
  1. public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)  
  2.         throws ServletException, IOException {  
  3.   
  4.     // Lazily initialize the delegate if necessary.  
  5.     Filter delegateToUse = null;  
  6.     synchronized (this.delegateMonitor) {  
  7.         if (this.delegate == null) {  
  8.             WebApplicationContext wac = findWebApplicationContext();  
  9.             if (wac == null) {  
  10.                 throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");  
  11.             }  
  12.             this.delegate = initDelegate(wac);  
  13.         }  
  14.         delegateToUse = this.delegate;  
  15.     }  
  16.   
  17.     // Let the delegate perform the actual doFilter operation.  
  18.     invokeDelegate(delegateToUse, request, response, filterChain);  
  19. }  

这里做了两件事: 
一、initDelegate(wac);//初始化FilterChainProxy 
Java代码   收藏代码
  1. protected Filter initDelegate(WebApplicationContext wac) throws ServletException {  
  2.     Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);  
  3.     if (isTargetFilterLifecycle()) {  
  4.         delegate.init(getFilterConfig());  
  5.     }  
  6.     return delegate;  
  7. }  

getTargetBeanName()返回的是Filter的name:springSecurityFilterChain 
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class); 
这里根据springSecurityFilterChain的bean name直接获取FilterChainProxy的实例。 
这里大家会产生疑问,springSecurityFilterChain这个bean在哪里定义的呢? 
此时似乎忽略了spring security的bean配置文件了 
Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans:beans xmlns="http://www.springframework.org/schema/security"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:beans="http://www.springframework.org/schema/beans"  
  5.        xsi:schemaLocation="  
  6.        http://www.springframework.org/schema/beans  
  7.        http://www.springframework.org/schema/beans/spring-beans.xsd  
  8.        http://www.springframework.org/schema/security  
  9.        http://www.springframework.org/schema/security/   
  10.               spring-security-3.0.xsd">  
  11.   <http auto-config="true">  
  12.     <intercept-url pattern="/*" access="ROLE_USER"/>  
  13.   </http>  
  14.   <authentication-manager alias="authenticationManager">  
  15.     <authentication-provider>  
  16.       <user-service>  
  17.         <user authorities="ROLE_USER" name="guest" password="guest"/>  
  18.       </user-service>  
  19.     </authentication-provider>  
  20.   </authentication-manager>   
  21. </beans:beans>  

这是最简单的配置了,同时也是解开springSecurityFilterChain这个bean没有定义的疑问了。 
这里主要利用了spring的自定义标签。具体参见: 
[url] http://www.w3school.com.cn/schema/schema_example.asp[/url] 
首先spring security的标签解析部分的源码包为: 
spring-security-config-3.0.2.RELEASE.jar 
这个jar包的META-INF目录下面有spring.handlers,spring.schemas两个文件,其中spring.schemas文件主要是标签的规范、约束;而spring.handlers这个文件时真正解析自定义标签的类,这个文件的内容为: 
Java代码   收藏代码
  1. http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler  

从这里可以看出来spring security的标签解析由org.springframework.security.config.SecurityNamespaceHandler 
来处理。该类实现接口:NamespaceHandler,spring中自定义标签都要实现该接口,这个接口有三个方法init、parse、decorate,其中init用于自定义标签的初始化,parse用于解析标签,decorate用于装饰。 
SecurityNamespaceHandler类的init方法完成了标签解析类的注册工作 
Java代码   收藏代码
  1.    public void init() {  
  2.        // Parsers  
  3.        parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());  
  4.        parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());  
  5.        parsers.put(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());  
  6.        parsers.put(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());  
  7.        parsers.put(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());  
  8.        parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());  
  9.        parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());  
  10.        parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());  
  11. //       registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());  
  12.   
  13.        // Only load the web-namespace parsers if the web classes are available  
  14.        if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {  
  15.            parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());  
  16.            parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());  
  17.            parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());  
  18.            filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();  
  19.            //registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());  
  20.        }  
  21.    }  

可以看出,http的标签解析类注册代码为: 
Java代码   收藏代码
  1. parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());  

authentication-manager的标签解析类注册代码为: 
Java代码   收藏代码
  1. parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());  

HttpSecurityBeanDefinitionParser的parse方法源码为: 
Java代码   收藏代码
  1. public BeanDefinition parse(Element element, ParserContext pc) {  
  2.         CompositeComponentDefinition compositeDef =  
  3.             new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));  
  4.         pc.pushContainingComponent(compositeDef);  
  5.         final Object source = pc.extractSource(element);  
  6.   
  7.         final String portMapperName = createPortMapper(element, pc);  
  8.         final UrlMatcher matcher = createUrlMatcher(element);  
  9.   
  10.         HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcher, portMapperName);  
  11.   
  12.         httpBldr.parseInterceptUrlsForEmptyFilterChains();  
  13.         httpBldr.createSecurityContextPersistenceFilter();  
  14.         httpBldr.createSessionManagementFilters();  
  15.   
  16.         ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();  
  17.         BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, null);  
  18.   
  19.         httpBldr.createServletApiFilter();  
  20.         httpBldr.createChannelProcessingFilter();  
  21.         httpBldr.createFilterSecurityInterceptor(authenticationManager);  
  22.   
  23.         AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,  
  24.                 httpBldr.isAllowSessionCreation(), portMapperName);  
  25.   
  26.         authBldr.createAnonymousFilter();  
  27.         authBldr.createRememberMeFilter(authenticationManager);  
  28.         authBldr.createRequestCache();  
  29.         authBldr.createBasicFilter(authenticationManager);  
  30.         authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);  
  31.         authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);  
  32.         authBldr.createX509Filter(authenticationManager);  
  33.         authBldr.createLogoutFilter();  
  34.         authBldr.createLoginPageFilterIfNeeded();  
  35.         authBldr.createUserServiceInjector();  
  36.         authBldr.createExceptionTranslationFilter();  
  37.   
  38.         List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();  
  39.   
  40.         unorderedFilterChain.addAll(httpBldr.getFilters());  
  41.         unorderedFilterChain.addAll(authBldr.getFilters());  
  42.   
  43.         authenticationProviders.addAll(authBldr.getProviders());  
  44.   
  45.         BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);  
  46.         requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache());  
  47.         unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));  
  48.   
  49.         unorderedFilterChain.addAll(buildCustomFilterList(element, pc));  
  50.   
  51.         Collections.sort(unorderedFilterChain, new OrderComparator());  
  52.         checkFilterChainOrder(unorderedFilterChain, pc, source);  
  53.   
  54.         List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();  
  55.   
  56.         for (OrderDecorator od : unorderedFilterChain) {  
  57.             filterChain.add(od.bean);  
  58.         }  
  59.   
  60.         ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();  
  61.         BeanDefinition universalMatch = new RootBeanDefinition(String.class);  
  62.         universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern());  
  63.         filterChainMap.put(universalMatch, filterChain);  
  64.   
  65.         registerFilterChainProxy(pc, filterChainMap, matcher, source);  
  66.   
  67.         pc.popAndRegisterContainingComponent();  
  68.         return null;  
  69.     }  

很多spring security的教程都会说http标签配置了auto-config="true"属性,spring security就会自动配置好了过滤器链。但是这些过滤器是如何添加到链中的呢,教程没说。 
但是上面的代码已经告诉我们,就在这里设置的 
Java代码   收藏代码
  1. httpBldr.createSecurityContextPersistenceFilter();  
  2. httpBldr.createSessionManagementFilters();  
  3. httpBldr.createServletApiFilter();  
  4. httpBldr.createChannelProcessingFilter();  
  5. httpBldr.createFilterSecurityInterceptor(authenticationManager);  
  6. …………  
  7. authBldr.createAnonymousFilter();  
  8. authBldr.createRememberMeFilter(authenticationManager);  
  9. authBldr.createRequestCache();  
  10. authBldr.createBasicFilter(authenticationManager);  
  11. authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);  
  12. authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);  
  13. authBldr.createX509Filter(authenticationManager);  
  14. authBldr.createLogoutFilter();  
  15. authBldr.createLoginPageFilterIfNeeded();  
  16. authBldr.createUserServiceInjector();  
  17. authBldr.createExceptionTranslationFilter();  

具体create分析下一篇再细说。接下来完成Filter的排序、并添加到filterChainMap集合中 
Java代码   收藏代码
  1. List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();  
  2.   
  3.         unorderedFilterChain.addAll(httpBldr.getFilters());  
  4.         unorderedFilterChain.addAll(authBldr.getFilters());  
  5.   
  6.         authenticationProviders.addAll(authBldr.getProviders());  
  7.   
  8.         BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);  
  9.         requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache());  
  10.         unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));  
  11.   
  12.         unorderedFilterChain.addAll(buildCustomFilterList(element, pc));  
  13.   
  14.         Collections.sort(unorderedFilterChain, new OrderComparator());  
  15.         checkFilterChainOrder(unorderedFilterChain, pc, source);  
  16.   
  17.         List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();  
  18.   
  19.         for (OrderDecorator od : unorderedFilterChain) {  
  20.             filterChain.add(od.bean);  
  21.         }  
  22.   
  23.         ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();  
  24.         BeanDefinition universalMatch = new RootBeanDefinition(String.class);  
  25.         universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern());  
  26.         filterChainMap.put(universalMatch, filterChain);  

此时,已经为FilterChainProxy提供了必须的参数,接下来就是该完成FilterChainProxy的bean定义过程了 
Java代码   收藏代码
  1. registerFilterChainProxy(pc, filterChainMap, matcher, source);  

Java代码   收藏代码
  1. private void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {  
  2.     if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {  
  3.         pc.getReaderContext().error("Duplicate <http> element detected", source);  
  4.     }  
  5.     //定义FilterChainProxy的BeanDefinition构造对象  
  6.      BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);  
  7.     fcpBldr.getRawBeanDefinition().setSource(source);  
  8.     fcpBldr.addPropertyValue("matcher", matcher);  
  9.     fcpBldr.addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));  
  10.     //注入过滤器链  
  11.     fcpBldr.addPropertyValue("filterChainMap", filterChainMap);  
  12.     BeanDefinition fcpBean = fcpBldr.getBeanDefinition();  
  13.     //注册bean  
  14.     pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));  
  15.     //注册bean的alias,其中别名为springSecurityFilterChain        
  16.     pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);  
  17. }  

这里需要说明的是BeanDefinitionBuilder类,该类能够动态创建spring的bean,并通过ParserContext完成bean的注册,而不需要在xml中进行配置。 
此时FilterChainProxy实例化过程已经完成。 
二、invokeDelegate(delegateToUse, request, response, filterChain); 
//调用代理类的doFilter方法 
Java代码   收藏代码
  1. protected void invokeDelegate(  
  2.         Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)  
  3.         throws ServletException, IOException {  
  4.     delegate.doFilter(request, response, filterChain);  
  5. }  

执行第一步获取的FilterChainProxy实例的doFilter方法。 

通过以上分析,对FilterChainProxy如何产生的,以及Spring Security的标签是如何解析有了大体的认识。 
具体标签的解析、Filter链的执行,下次再更新……
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值