spring security 中spring bean组成的过滤器链如何初始化的

pring security 中spring bean组成的过滤器链如何初始化的

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>

这个过滤器的名字必须是springSecurityFilterChain,这个是spirng 安全框架定义的,定义的 地方:

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";

spring给打注释也说的很明白了.

既然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();

就是我 们在web.xml中配置的名字: springSecurityFilterChain .

	// 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中寻找this.delegate,即代理的真实对象:/ org.springframework.security.filterChainProxy


那我们就要知道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>

们也知道如何配置spirng 安全组件,简化的配置如下:

 <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>

那我们就要知道srp ring是如何解析这些xml,实例化这些类的.

spirng解析这些xml的思路主要是:NamespaceHandler、BeanDefinitionParser的各种子类。

由spirng提供的文件spirng.handlers文件内容:

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

我们必须从 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>

代码中会向spring容器注册org.springframework.security.filterChainProxy实例。

此类中有一个变量:

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类。


你可能感兴趣的:(spring,spring,Security,Security,过滤器链)