Spring Security中代理过滤器是通过FilterChain如何工作的

我们在搭建Spring Security框架的第一步配置是在项目的web.xml添加代理过滤器,配置如下

  
  	springSecurityFilterChain
  	org.springframework.web.filter.DelegatingFilterProxy
  
  
  	springSecurityFilterChain
  	/*
  

由此我我们可以得出一个结果,所有的请求都会经过DelegatingFilterProxy,从而实现权限的控制。让我们来看一下DelegatingFilterProxy的doFilter方法是如何实现的。

	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) {
				if (this.delegate == null) {
					WebApplicationContext wac = findWebApplicationContext();
					if (wac == null) {
						throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
					}
					this.delegate = initDelegate(wac);
				}
				delegateToUse = this.delegate;
			}
		}

		// Let the delegate perform the actual doFilter operation.
		invokeDelegate(delegateToUse, request, response, filterChain);
	}

最后调用invokeDelegate方法,让我们来看一下invokeDelegate方法。

	protected void invokeDelegate(
			Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		delegate.doFilter(request, response, filterChain);
	}

由此可见,请求在进入DelegatingFilterProxy后是实际上由delegate做的处理。那这个delegate是如何来得呢?由上面的

this.delegate = initDelegate(wac);
可以看出,是通过initDelegate方法得到的。

	protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

由此可见,delegate是在Spring容器的一个名为getTargetBeanName方法返回的字符串的bean.而这个方法的返回值就是我们在web.xml配置的的值springSecurityFilterChain。现在我们来探究一下这个bean的出处。

我们在spring的配置文件中搜索,发现并没有注册名为springSecurityFilterChain的bean,可以得出这个bean不是我们通过配置得到的,而是从代码层面实现的。

所以我们唯一的切入点就是为Spring的配置文件添加的Spring Security添加的xsd了。对Spring配置文件的解析都是通过BeanDefinitionParser来实现的,所以我们发现了一个叫做HttpSecurityBeanDefinitionParser的一个类。

    @SuppressWarnings({"unchecked"})
    public BeanDefinition parse(Element element, ParserContext pc) {
        CompositeComponentDefinition compositeDef =
            new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
        pc.pushContainingComponent(compositeDef);

       //此方法就是用来将注册名为springSecurityFilterChain的bean.
        registerFilterChainProxyIfNecessary(pc, pc.extractSource(element));

        // Obtain the filter chains and add the new chain to it
        BeanDefinition listFactoryBean = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAINS);
        List filterChains = (List)
                listFactoryBean.getPropertyValues().getPropertyValue("sourceList").getValue();

        filterChains.add(createFilterChain(element, pc));

        pc.popAndRegisterContainingComponent();
        return null;
    }

    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));
        //此段代码注册一个类进入到Spring的容器中
        pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
    }
这个类就是Spring Security进行过滤链初始化配置的的核心类。其中createFilterChain方法就是对Security配置文件解析以及自定义过滤器、默认过滤器进行添加的核心方法。



你可能感兴趣的:(spring-security)