Spring Security3中的-authentication-manager标签详解

讲解完http标签的解析过程,authentication-manager标签解析部分就很容易理解了 
authentication-manager标签在spring的配置文件中的定义一般如下

1 <authentication-manager alias="authenticationManager">
2     <authentication-provider user-service-ref="userDetailsManager"/>
3 </authentication-manager>   

authentication-manager标签的解析类是: 
org.springframework.security.config.authentication.AuthenticationManagerBeanDefinitionParser 
具体解析方法parse的代码为

 1 public BeanDefinition parse(Element element, ParserContext pc) {
 2         Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
 3                 "AuthenticationManager has already been registered!");
 4         pc.pushContainingComponent(new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)));
 5         //构造ProviderManager的BeanDefinition
 6         BeanDefinitionBuilder providerManagerBldr = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
 7         //获取alias属性
 8         String alias = element.getAttribute(ATT_ALIAS);
 9         //检查session-controller-ref属性,提示通过标签<concurrent-session-control>取代
10         checkForDeprecatedSessionControllerRef(element, pc);
11         List<BeanMetadataElement> providers = new ManagedList<BeanMetadataElement>();
12         NamespaceHandlerResolver resolver = pc.getReaderContext().getNamespaceHandlerResolver();
13         //获取authentication-manager的子节点
14         NodeList children = element.getChildNodes();
15         //循环节点,一般子节点主要是authentication-provider或者
16          //ldap-authentication-provider
17         for (int i = 0; i < children.getLength(); i++) {
18             Node node = children.item(i);
19             if (node instanceof Element) {
20                 Element providerElt = (Element)node;
21                 //判断子标签是否有ref属性,如果有,则直接将ref属性
22                    //引用的bean id添加到providers集合中
23                 if (StringUtils.hasText(providerElt.getAttribute(ATT_REF))) {
24                     providers.add(new RuntimeBeanReference(providerElt.getAttribute(ATT_REF)));
25                 } else {
26                     //如果没有ref属性,则通过子标签的解析类完成标签解析
27                        //如子标签:authentication-provider,解析过程在后面
28                     BeanDefinition provider = resolver.resolve(providerElt.getNamespaceURI()).parse(providerElt, pc);
29                     Assert.notNull(provider, "Parser for " + providerElt.getNodeName() + " returned a null bean definition");
30                     String id = pc.getReaderContext().generateBeanName(provider);
31                     //注册provider的BeanDefinition
32                     pc.registerBeanComponent(new BeanComponentDefinition(provider, id));
33                     //添加注册过的bean到provider集合中
34                     providers.add(new RuntimeBeanReference(id));
35                 }
36             }
37         }
38
39         if (providers.isEmpty()) {
40             providers.add(new RootBeanDefinition(NullAuthenticationProvider.class));
41         }
42
43         providerManagerBldr.addPropertyValue("providers", providers);
44         //添加默认的事件发布类
45         BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
46         String id = pc.getReaderContext().generateBeanName(publisher);
47         pc.registerBeanComponent(new BeanComponentDefinition(publisher, id));
48         //将事件发布类的bean注入到ProviderManager的
49          //authenticationEventPublisher属性中
50         providerManagerBldr.addPropertyReference("authenticationEventPublisher", id);
51         //注册ProviderManager的bean
52         pc.registerBeanComponent(
53                 new BeanComponentDefinition(providerManagerBldr.getBeanDefinition(), BeanIds.AUTHENTICATION_MANAGER));
54
55         if (StringUtils.hasText(alias)) {
56             pc.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
57             pc.getReaderContext().fireAliasRegistered(BeanIds.AUTHENTICATION_MANAGER, alias, pc.extractSource(element));
58         }
59
60         pc.popAndRegisterContainingComponent();
61
62         return null;
63     }  

通过上面的代码片段,能够知道authentication-manager标签解析的步骤是

1.构造ProviderManager的BeanDefinition

2.循环authentication-manager的子标签,构造provider的BeanDefinition,并添加到providers集合中

3.将第2步的providers设置为ProviderManager的providers属性

4.构造异常事件发布类DefaultAuthenticationEventPublisher的BeanDefinition,并设置为ProviderManager的属性authenticationEventPublisher

5.通过registerBeanComponent方法完成bean的注册任务

authentication-provider标签的解析类为 
org.springframework.security.config.authentication.AuthenticationProviderBeanDefinitionParser

 1 public BeanDefinition parse(Element element, ParserContext parserContext) {
 2     //首先构造DaoAuthenticationProvider的BeanDefinition
 3     RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
 4     authProvider.setSource(parserContext.extractSource(element));
 5     //获取password-encoder子标签
 6     Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
 7
 8     if (passwordEncoderElt != null) {
 9         //如果有password-encoder子标签,把解析任务交给
10           //PasswordEncoderParser完成
11         PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, parserContext);
12         authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
13         //如果有salt-source标签,将值注入到saltSource属性中
14         if (pep.getSaltSource() != null) {
15             authProvider.getPropertyValues().addPropertyValue("saltSource", pep.getSaltSource());
16         }
17     }
18     //下面获取子标签user-service、jdbc-user-service、ldap-user-service
19     Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
20     Element jdbcUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
21     Element ldapUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
22
23     String ref = element.getAttribute(ATT_USER_DETAILS_REF);
24
25     if (StringUtils.hasText(ref)) {
26         if (userServiceElt != null || jdbcUserServiceElt != null || ldapUserServiceElt != null) {
27             parserContext.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
28                     "elements ‘" + Elements.USER_SERVICE + "‘, ‘" + Elements.JDBC_USER_SERVICE + "‘ or ‘" +
29                     Elements.LDAP_USER_SERVICE + "‘", element);
30         }
31     } else {
32         // Use the child elements to create the UserDetailsService
33         AbstractUserDetailsServiceBeanDefinitionParser parser = null;
34         Element elt = null;
35         //下面的if语句,主要是根据子标签的不同,选择子标签对应的解析器处理
36         if (userServiceElt != null) {
37             elt = userServiceElt;
38             parser = new UserServiceBeanDefinitionParser();
39         } else if (jdbcUserServiceElt != null) {
40             elt = jdbcUserServiceElt;
41             parser = new JdbcUserServiceBeanDefinitionParser();
42         } else if (ldapUserServiceElt != null) {
43             elt = ldapUserServiceElt;
44             parser = new LdapUserServiceBeanDefinitionParser();
45         } else {
46             parserContext.getReaderContext().error("A user-service is required", element);
47         }
48
49         parser.parse(elt, parserContext);
50         ref = parser.getId();
51         String cacheRef = elt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
52
53         if (StringUtils.hasText(cacheRef)) {
54             authProvider.getPropertyValues().addPropertyValue("userCache", new RuntimeBeanReference(cacheRef));
55         }
56     }
57     //将解析后的bean id注入到userDetailsService属性中
58     authProvider.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(ref));
59     return authProvider;
60 }  

如果学习过acegi的配置,应该知道,acegi有这么一段配置

1 <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
2    <property name="providers">
3       <list>
4          <ref local="daoAuthenticationProvider"/>
5         <ref local="anonymousAuthenticationProvider"/>
6       </list>
7    </property>
8 </bean>  

实际上authentication-manager标签所要达到的目标就是构造上面的bean。其中anonymousAuthenticationProvider是在http解析过程添加的。

其实可以完全像acegi那样自定义每个bean。

1 <authentication-manager alias="authenticationManager">
2     <authentication-provider user-service-ref="userDetailsManager"/>
3 </authentication-manager>  

上面的标签如果用bean来定义,则可以完全由下面的xml来替代。

 1 <bean id="org.springframework.security.authenticationManager" class="org.springframework.security.authentication.ProviderManager">
 2         <property name="authenticationEventPublisher" ref="defaultAuthenticationEventPublisher"></property>
 3         <property name="providers">
 4             <list>
 5                 <ref local="daoAuthenticationProvider"/>
 6                 <ref local="anonymousAuthenticationProvider"/>
 7             </list>
 8         </property>
 9     </bean>
10
11     <bean id="defaultAuthenticationEventPublisher" class="org.springframework.security.authentication.DefaultAuthenticationEventPublisher"></bean>
12
13     <bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
14         <property name="key"><value>work</value></property>
15     </bean>
16
17     <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
18         <property name="userDetailsService" ref="userDetailsManager"></property>
19     </bean>  

需要注意的是anonymousAuthenticationProvider的bean中,需要增加key属性。如果采用authentication-manager标签的方式,key虽然没有定义,在增加AnonymousAuthenticationFilter过滤器中,是通过java.security.SecureRandom.nextLong()来生成的。

显而易见,如果采用bean的方式来定义,非常复杂,而且需要了解底层的组装过程才行,不过能够提高更大的扩展性。采用authentication-manager标签的方式,很简洁,只需要提供UserDetailsService即可。

时间: 2024-10-14 03:23:04

Spring Security3中的-authentication-manager标签详解的相关文章

技术分享:html中的Map,area标签详解

area标签详解 一.界说和用法 html中的Map.> 界说一个客户端图画映射.图画映射(image-map指带有可点击区域的一幅图画. 二.脚本示例: shqpe特点的设置阐明0.: 1.rect界说一个矩形区域.右下角的坐标,coord特点设置值为矩形的左上角.各个坐标值之间用逗号分隔; coord特点设置值为多边形各项极点的坐标值2.poli界说一个多边形区域.; 3.circl界说一格圆形区域.前两个参数分别为圆心的横,coord特点设置值为圆心坐标及半径.纵坐标,第三个参数为半径.

企业分布式微服务云SpringCloud SpringBoot mybatis (十四)Spring Boot中使用MyBatis注解配置详解

传参方式 下面通过几种不同传参方式来实现前文中实现的插入操作. 使用@Param 在之前的整合示例中我们已经使用了这种最简单的传参方式,如下: @Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})") int insert(@Param("name") String name, @Param("age") Integer age); 这种方式很好理解,@Param中定义的name

spring中Bean的注入参数详解

字面值    一般指可用字符串表示的值,这些值可以通过<value>元素标签进行注入.在默认情况下,基本数据类型及其封装类.String等类型都可以采取字面值注入的方式,Spring容器在内部为字面值提供了编辑器,它可以将以字符串表示的字面值转换为内部变量的相应类型.    配置信息:    <bean id="car" class="com.luxl.domain.Car">        <property name="m

HTML 中的marquee标签详解

该标签不是HTML3.2的一部分,并且只支持MSIE3以后内核,所以如果你使用非IE内核浏览器(如:Netscape)可能无法看到下面一些很有意思的效果 该标签是个容器标签 语法: <marquee></marquee> 以下是一个最简单的例子: 代码如下: <marquee><font size=+3 color=red>Hello, World</font></marquee> 下面这两个事件经常用到: onMouseOut=&q

【转载】html中object标签详解

[转载自http://blog.csdn.net/soliy/archive/2010/03/22/5404183.aspx] html标签之Object标签详解 作者:网络    出处:网络    2010年3月22日13:36:29 定义和用法定义一个嵌入的对象.请使用此元素向您的 XHTML 页面添加多媒体.此元素允许您规定插入 HTML 文档中的对象的数据和参数,以及可用来显示和操作数据的代码.<object> 标签用于包含对象,比如图像.音频.视频.Java applets.Acti

struts2中ognl标签详解

<body> <s:set name="age" value="61" /> <!-- if elseif else 参数test:决定标志里的内容是否显示的表达式,类型boolean 注:else标志没有这个参数 --> <h3>if语句</h3> <s:if test="{age>60}"> 老年人 </s:if> <s:elseif test=&

Meta标签详解

Meta标签详解,在网上转的,希望对大家有用 引言 您的个人网站即使做得再精彩,在"浩瀚如海"的网络空间中,也如一叶扁舟不易为人发现,如何推广个人网站,人们首先想到的方法无外乎以下几种: ● 在搜索引擎中登录自己的个人网站 ● 在知名网站加入你个人网站的链接 ● 在论坛中发帖子宣传你的个人网站 很多人却忽视了HTML标签META的强大功效,一个好的META标签设计可以大大提高你的个人网站被搜索到的可能性,有兴趣吗,谁我来重新认识一下META标签吧! META标签是HTML语言HEAD区

meta标签详解(meta标签的作用)///////////////////////////转

meta标签详解(meta标签的作用) 很多人却忽视了HTML标签META的强大功效,一个好的META标签设计可以大大提高你的个人网站被搜索到的可能性,有兴趣吗,谁我来重新认识一下META标签吧 您的个人网站即使做得再精彩,在“浩瀚如海”的网络空间中,也如一叶扁舟不易为人发现,如何推广个人网站,人们首先想到的方法无外乎以下几种: ● 在搜索引擎中登录自己的个人网站 ● 在知名网站加入你个人网站的链接 ● 在论坛中发帖子宣传你的个人网站 很多人却忽视了HTML标签META的强大功效,一个好的MET

网页设计:Meta标签详解

很多人忽视了HTML标签META的强大功效,一个好的META标签设计可以大大提高你的个人网站被搜索到的可能性,有兴趣吗,谁我来重新认识一下META标签吧! META标签是HTML语言HEAD区的一个辅助性标签,它位于HTML文档头部的<HEAD>标记和<TITLE>标记之间,它提供用户不可见的信息.meta标签通常用来为搜索引擎robots定义页面主题,或者是定义用户浏览器上的cookie:它可以用于鉴别作者,设定页面格式,标注内容提要和关键字:还可以设置页面使其可以根据你定义的时

&lt;body&gt;标签详解与HTML常用的控制标记

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-