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

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

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

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                  http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <security:http>

        <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
        <!-- 开启表单登录: 会自动生成一个登录页面 -->
        <security:form-login />
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>

                <security:user name="admin" password="admin" authorities="ROLE_ADMIN"/>
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

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

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

然后我们可以在spring security的org.springframework.security.config包下面找到一个名为spring.handlers的文件

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

由此可以得知,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了

 

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值