分析spring security框架的filter的名字为什么必须是springSecurityFilterChain

  在很多spring security框架学习资料里面,我们都会看到一句话那就是在web.xml中配置加载spring security框架的时候,所配置的Filter名字必须是springSecurityFilterChain,如果我们的名字没有使用固定的springSecurityFilterChain,比如名字改成springSecurityFilterChain1,如图:

分析spring security框架的filter的名字为什么必须是springSecurityFilterChain_第1张图片

这个时候加载过程中就会报错

从报错信息中我们可以得知,如果我们使用的名称是springSecurityFilterChain,那么我们就应该去加载一个id为springSecurityFilterChain的bean。但是,查看我们的spring-security.xml的配置文件,你根本找不到这个id为springSecurityFilterChain的bean,甚至连bean标签都找不到,如下便是spring-security.xml的内容




    

        
        
        
    

    
        
            

                
            
        
    

在查找了很多资料和分析了spring security框架源码之后,终于找到了这个隐藏着的id为springSecurityFilterChain的bean是如何被加载的

首先,我们看到spring-security.xml中有这样一个标签 ,然后我们从配置文件上可以看出,这里的security实际上是一个url的别名,这个url就是配置文件开头部分写着的xmlns:security="http://www.springframework.org/schema/security,也就是说等价于

然后我们可以在spring security的org.springframework.security.config包下面找到一个名为spring.handlers的文件分析spring security框架的filter的名字为什么必须是springSecurityFilterChain_第2张图片

点开这个文件,我们可以看到如下内容

由此可以得知,http://www.springframework.org/schema/security这个url实际上是指向了org.springframework.security.config包下的SecurityNameSpaceHandler类,接下来我们找到这个类,可以在这个类中找到如下这段代码

private void loadParsers() {
    this.parsers.put("ldap-authentication-provider", new LdapProviderBeanDefinitionParser());
    this.parsers.put("ldap-server", new LdapServerBeanDefinitionParser());
    this.parsers.put("ldap-user-service", new LdapUserServiceBeanDefinitionParser());
    this.parsers.put("user-service", new UserServiceBeanDefinitionParser());
    this.parsers.put("jdbc-user-service", new JdbcUserServiceBeanDefinitionParser());
    this.parsers.put("authentication-provider", new AuthenticationProviderBeanDefinitionParser());
    this.parsers.put("global-method-security", new GlobalMethodSecurityBeanDefinitionParser());
    this.parsers.put("authentication-manager", new AuthenticationManagerBeanDefinitionParser());
    this.parsers.put("method-security-metadata-source", new MethodSecurityMetadataSourceBeanDefinitionParser());
    if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", this.getClass().getClassLoader())) {
        this.parsers.put("debug", new DebugBeanDefinitionParser());
        this.parsers.put("http", new HttpSecurityBeanDefinitionParser());
        this.parsers.put("http-firewall", new HttpFirewallBeanDefinitionParser());
        this.parsers.put("filter-security-metadata-source", new FilterInvocationSecurityMetadataSourceParser());
        this.parsers.put("filter-chain", new FilterChainBeanDefinitionParser());
        this.filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
    }

    if (ClassUtils.isPresent("org.springframework.messaging.Message", this.getClass().getClassLoader())) {
        this.parsers.put("websocket-message-broker", new WebSocketMessageBrokerSecurityBeanDefinitionParser());
    }

}

其中this.parsers.put("http", new HttpSecurityBeanDefinitionParser());这句代码就是解决我们问题的关键,从这句代码可以得知,在是用属性为http的标签的时候,实际上是去创建了一个HttpSecurityBeanDefinitionParser类的对象,接下来我们找到这个类,可以在这个类中看到段静态代码,内容如下:

static void registerFilterChainProxyIfNecessary(ParserContext pc, Object source) {
    if (!pc.getRegistry().containsBeanDefinition("org.springframework.security.filterChainProxy")) {
        BeanDefinition listFactoryBean = new RootBeanDefinition(ListFactoryBean.class);
        listFactoryBean.getPropertyValues().add("sourceList", new ManagedList());
        pc.registerBeanComponent(new BeanComponentDefinition(listFactoryBean, "org.springframework.security.filterChains"));
        BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
        fcpBldr.getRawBeanDefinition().setSource(source);
        fcpBldr.addConstructorArgReference("org.springframework.security.filterChains");
        fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(DefaultFilterChainValidator.class));
        BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
        pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, "org.springframework.security.filterChainProxy"));
        pc.getRegistry().registerAlias("org.springframework.security.filterChainProxy", "springSecurityFilterChain");
    }
}

可见,在创建HttpSecurityBeanDefinitionParser类的对象的时候,就已经注册了一个名为springSecurityFilterChain的bean了

 

你可能感兴趣的:(SpringSecurity)