spring security 框架的安全是基于过滤器链的,但此filter是被spring容器托管的.
一般我们会在web.xml文件中配置一个代理过滤器:
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
org.springframework.security.config.BeanIds中,
/** External alias for FilterChainProxy bean, for use in web.xml files */ public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";
既然org.springframework.web.filter.DelegatingFilterProxy这个代理类是入口点,那我们就进去看看如何执行的吧.如何把spring bean定义的安全过滤器链组装的.
此类中的初始化函数:
@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(); //==>springSecurityFilterChain web.xml配置文件中的过滤器名字,也是所代理的spring bean } // 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); } } } }
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); }
那我们就要知道spring root context 怎么初始话这个真实对象的.既然文档说是从spring root context来寻找的,那spirng 安全的组件最好配置在spring root context中,即:(spring 还有web context呢)
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:rootContextConfig/spring-context.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
<security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/hello" access="hasRole('ROLE_SCARVAREZ_MEMBER')" /> <security:expression-handler ref=""/> </security:http> <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="doctor" password="doctor" authorities="ROLE_SCARVAREZ_MEMBER"/> </security:user-service> </security:authentication-provider> </security:authentication-manager>
spirng解析这些xml的思路主要是:NamespaceHandler、BeanDefinitionParser的各种子类。
由spirng提供的文件spirng.handlers文件内容:
http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler
org.springframework.security.config.http.HttpSecurityBeanDefinitionParser好了,
在
<span style="font-size:18px;">public BeanDefinition parse(Element element, ParserContext pc) </span>
代码内有一行关键点:
<span style="font-size:18px;"> registerFilterChainProxyIfNecessary(pc, pc.extractSource(element)); //这里是创建FilterChainProxy类实例的入口.</span>
<span style="font-size:18px;">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); } }</span>
此类中有一个变量:
private List<SecurityFilterChain> filterChains;
这个是spring解析spirng 安全xml或默认初始话的spirng bean组成的,会被依赖注入到filterChainProxy。
会被注入哪些bean,请参看HttpSecurityBeanDefinitionParser类中的
private BeanReference createFilterChain(Element element, ParserContext pc)
方法,关键是调用的org.springframework.security.config.http.HttpConfigurationBuilder类。