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

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

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

 public BeanDefinition parse(Element element, ParserContext pc) {
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
"AuthenticationManager has already been registered!");
pc.pushContainingComponent(new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)));
//构造ProviderManager的BeanDefinition
BeanDefinitionBuilder providerManagerBldr = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
//获取alias属性
String alias = element.getAttribute(ATT_ALIAS);
//检查session-controller-ref属性,提示通过标签<concurrent-session-control>取代
checkForDeprecatedSessionControllerRef(element, pc);
List<BeanMetadataElement> providers = new ManagedList<BeanMetadataElement>();
NamespaceHandlerResolver resolver = pc.getReaderContext().getNamespaceHandlerResolver();
//获取authentication-manager的子节点
NodeList children = element.getChildNodes();
//循环节点,一般子节点主要是authentication-provider或者
//ldap-authentication-provider
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node instanceof Element) {
Element providerElt = (Element)node;
//判断子标签是否有ref属性,如果有,则直接将ref属性
//引用的bean id添加到providers集合中
if (StringUtils.hasText(providerElt.getAttribute(ATT_REF))) {
providers.add(new RuntimeBeanReference(providerElt.getAttribute(ATT_REF)));
} else {
//如果没有ref属性,则通过子标签的解析类完成标签解析
//如子标签:authentication-provider,解析过程在后面
BeanDefinition provider = resolver.resolve(providerElt.getNamespaceURI()).parse(providerElt, pc);
Assert.notNull(provider, "Parser for " + providerElt.getNodeName() + " returned a null bean definition");
String id = pc.getReaderContext().generateBeanName(provider);
//注册provider的BeanDefinition
pc.registerBeanComponent(new BeanComponentDefinition(provider, id));
//添加注册过的bean到provider集合中
providers.add(new RuntimeBeanReference(id));
}
}
} if (providers.isEmpty()) {
providers.add(new RootBeanDefinition(NullAuthenticationProvider.class));
} providerManagerBldr.addPropertyValue("providers", providers);
//添加默认的事件发布类
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
String id = pc.getReaderContext().generateBeanName(publisher);
pc.registerBeanComponent(new BeanComponentDefinition(publisher, id));
//将事件发布类的bean注入到ProviderManager的
//authenticationEventPublisher属性中
providerManagerBldr.addPropertyReference("authenticationEventPublisher", id);
//注册ProviderManager的bean
pc.registerBeanComponent(
new BeanComponentDefinition(providerManagerBldr.getBeanDefinition(), BeanIds.AUTHENTICATION_MANAGER)); if (StringUtils.hasText(alias)) {
pc.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
pc.getReaderContext().fireAliasRegistered(BeanIds.AUTHENTICATION_MANAGER, alias, pc.extractSource(element));
} pc.popAndRegisterContainingComponent(); return null;
}

通过上面的代码片段,能够知道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

 public BeanDefinition parse(Element element, ParserContext parserContext) {
//首先构造DaoAuthenticationProvider的BeanDefinition
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
authProvider.setSource(parserContext.extractSource(element));
//获取password-encoder子标签
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER); if (passwordEncoderElt != null) {
//如果有password-encoder子标签,把解析任务交给
//PasswordEncoderParser完成
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, parserContext);
authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
//如果有salt-source标签,将值注入到saltSource属性中
if (pep.getSaltSource() != null) {
authProvider.getPropertyValues().addPropertyValue("saltSource", pep.getSaltSource());
}
}
//下面获取子标签user-service、jdbc-user-service、ldap-user-service
Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
Element jdbcUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
Element ldapUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE); String ref = element.getAttribute(ATT_USER_DETAILS_REF); if (StringUtils.hasText(ref)) {
if (userServiceElt != null || jdbcUserServiceElt != null || ldapUserServiceElt != null) {
parserContext.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
"elements '" + Elements.USER_SERVICE + "', '" + Elements.JDBC_USER_SERVICE + "' or '" +
Elements.LDAP_USER_SERVICE + "'", element);
}
} else {
// Use the child elements to create the UserDetailsService
AbstractUserDetailsServiceBeanDefinitionParser parser = null;
Element elt = null;
//下面的if语句,主要是根据子标签的不同,选择子标签对应的解析器处理
if (userServiceElt != null) {
elt = userServiceElt;
parser = new UserServiceBeanDefinitionParser();
} else if (jdbcUserServiceElt != null) {
elt = jdbcUserServiceElt;
parser = new JdbcUserServiceBeanDefinitionParser();
} else if (ldapUserServiceElt != null) {
elt = ldapUserServiceElt;
parser = new LdapUserServiceBeanDefinitionParser();
} else {
parserContext.getReaderContext().error("A user-service is required", element);
} parser.parse(elt, parserContext);
ref = parser.getId();
String cacheRef = elt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF); if (StringUtils.hasText(cacheRef)) {
authProvider.getPropertyValues().addPropertyValue("userCache", new RuntimeBeanReference(cacheRef));
}
}
//将解析后的bean id注入到userDetailsService属性中
authProvider.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(ref));
return authProvider;
}

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

 <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
<ref local="anonymousAuthenticationProvider"/>
</list>
</property>
</bean>

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

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

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

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

 <bean id="org.springframework.security.authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<property name="authenticationEventPublisher" ref="defaultAuthenticationEventPublisher"></property>
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
<ref local="anonymousAuthenticationProvider"/>
</list>
</property>
</bean> <bean id="defaultAuthenticationEventPublisher" class="org.springframework.security.authentication.DefaultAuthenticationEventPublisher"></bean> <bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key"><value>work</value></property>
</bean> <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsManager"></property>
</bean>

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

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

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

  1. Spring Boot中使用MyBatis注解配置详解(1)

    之前在Spring Boot中整合MyBatis时,采用了注解的配置方式,相信很多人还是比较喜欢这种优雅的方式的,也收到不少读者朋友的反馈和问题,主要集中于针对各种场景下注解如何使用,下面就对几种常见 ...

  2. Spring Boot中使用MyBatis注解配置详解

    传参方式 下面通过几种不同传参方式来实现前文中实现的插入操作. 使用@Param 在之前的整合示例中我们已经使用了这种最简单的传参方式,如下: @Insert("INSERT INTO US ...

  3. 【转载】html中object标签详解

    [转载自http://blog.csdn.net/soliy/archive/2010/03/22/5404183.aspx] html标签之Object标签详解 作者:网络    出处:网络     ...

  4. JSP页面中的Meta标签详解

    Meta标签详解 相信大家在平时开发中最常接触的页面就是html和jsp了,可在这两个页面中有一个Meta标签你天天都会看见,可是你真的了解这个标签的一些其他用处吗?今天给大家介绍一些该标签的其他应用 ...

  5. 转:springmvc常用注解标签详解

    Spring5:@Autowired注解.@Resource注解和@Service注解 - IT·达人 - 博客园--这篇顺序渐进,讲得超级好--此人博客很不错http://www.cnblogs.c ...

  6. Meta标签详解(HTML JAVASCRIPT)

    Meta标签详解,在网上转的,希望对大家有用 您的个人网站即使做得再精彩,在“浩瀚如海”的网络空间中,也如一叶扁舟不易为人发现,如何推广 个人网站,人们首先想到的方法无外乎以下几种: ● 在搜索引擎中 ...

  7. 网页设计:Meta标签详解

    很多人忽视了HTML标签META的强大功效,一个好的META标签设计可以大大提高你的个人网站被搜索到的可能性,有兴趣吗,谁我来重新认识一下META标签吧! META标签是HTML语言HEAD区的一个辅 ...

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

    meta标签详解(meta标签的作用) 很多人却忽视了HTML标签META的强大功效,一个好的META标签设计可以大大提高你的个人网站被搜索到的可能性,有兴趣吗,谁我来重新认识一下META标签吧   ...

  9. JQuery在循环中绑定事件的问题详解

    JQuery在循环中绑定事件的问题详解 有个页面上需要N个DOM,每个DOM里面的元素ID都要以数字结尾,比如说 ? 1 2 3 <input type="text" nam ...

  10. SVN中tag branch trunk用法详解

    SVN中tag branch trunk用法详解 2010-05-24 18:32 佚名 字号:T | T 本文向大家简单介绍一下SVN中tag branch trunk用法,SVN中tag bran ...

随机推荐

  1. 使用Microsoft Fakes隔离测试代码

    在单元测试(Unit Test)中我们遇到的问题之一是:假如被测试组件(类或项目)为A,组件A依赖于组件B,那么在组件A的单元测试ATest中测试A时,也需要依赖于B,在B发生改动后,就可能影响到A的 ...

  2. 基于C#和Asp.NET MVC开发GPS部标监控平台

    基于交通部796标准开发部标监控平台,选择开发语言和技术也是团队要思考的因素,其实这由团队自己擅长的技术来决定,如果擅长C#和Asp.NET, 当然开发效率就高很多.当然了技术选型一定要选用当前主流的 ...

  3. js 斐波那契数列(兔子问题)

    对于JS初学者来说,斐波那契数列一直是个头疼的问题,总是理不清思路. 希望看完这篇文章之后会对你有帮助. 什么是斐波那契数列 : 答: 斐波那契数列,又称黄金分割数列.因数学家列昂纳多·斐波那契(Le ...

  4. Leetcode: Android Unlock Patterns

    Given an Android 3x3 key ≤ m ≤ n ≤ , count the total number of unlock patterns of the Android lock s ...

  5. iis部署文件支持svg

    今测试的一个asp网站代码,在本地一切正常,可是上传到服务器上之后就发现一些图标不显示了.图片在文件路径存在,但是访问不了,经查询.svg的图片想要在iis(iis7支持)上能正常打开,还需要做一下映 ...

  6. android aidl

    参考: http://blog.csdn.net/u014614038/article/details/48399935 本文提供了一个关于AIDL使用的简单易懂的例子,分为客户端和服务端两部分,分别 ...

  7. Java多线程开发系列之一:走进多线程

    对编程语言的基础知识:分支.选择.循环.面向对象等基本概念理解后,我们需要对java高级编程有一定的学习,这里不可避免的要接触到多线程开发. 由于多线程开发整体的系统比较大,我会写一个系列的文章总结介 ...

  8. html5,video元素

    <video src="1.mp4" controls="" width="500"  height="300" ...

  9. response.write();改变页面布局的原因及解法

    Response.Write ,在ASP.NET 中不要随便使用 Response.Write,其原因是它会打乱 ASP.NET 的输出流顺序,在aspx.cs 中使用 Response.Write ...

  10. base64与byte[]之间转换

    主要是根据BASE64Encoder 和BASE64Decoder 进行操作实现,具体例子如下: BASE64Encoder encode = new BASE64Encoder(); //将byte ...