spring security 框架的安全是基于过滤器链的,但此filter是被spring容器托管的.
一般我们会在web.xml文件中配置一个代理过滤器:
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
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呢)
contextConfigLocation
classpath:rootContextConfig/spring-context.xml
org.springframework.web.context.ContextLoaderListener
spirng解析这些xml的思路主要是:NamespaceHandler、BeanDefinitionParser的各种子类。
由spirng提供的文件spirng.handlers文件内容:
http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler
org.springframework.security.config.http.HttpSecurityBeanDefinitionParser好了,
在
public BeanDefinition parse(Element element, ParserContext pc)
代码内有一行关键点:
registerFilterChainProxyIfNecessary(pc, pc.extractSource(element)); //这里是创建FilterChainProxy类实例的入口.
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);
}
}
此类中有一个变量:
private List
这个是spring解析spirng 安全xml或默认初始话的spirng bean组成的,会被依赖注入到filterChainProxy。
会被注入哪些bean,请参看HttpSecurityBeanDefinitionParser类中的
private BeanReference createFilterChain(Element element, ParserContext pc)
方法,关键是调用的org.springframework.security.config.http.HttpConfigurationBuilder类。