讲解完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. Python —条件语句

    条件语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空(null ...

  2. HDOJ 1004 Let the Balloon Rise

    Problem Description Contest time again! How excited it is to see balloons floating around. But to te ...

  3. Asp.Net Mvc4 Webapi Request获取参数

    最近用mvc4中的WEBAPI,发现接收参数不是很方便,跟传统的request.querystring和request.form有很大区别,在网上搜了一大圈,各种方案都有,但不是太详细,于是跟踪Act ...

  4. Ubuntu下查看机器信息

    原文地址 测试机器的硬件信息 查看CPU信息(看到有8个逻辑CPU, 也知道了CPU型号)   # cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq ...

  5. 代码审计之SQL注入

    0x00概况说明 0x01报错注入及利用 环境说明 kali LAMP 0x0a 核心代码 现在注入的主要原因是程序员在写sql语句的时候还是通过最原始的语句拼接来完成,另外SQL语句有Select. ...

  6. cmd光标移动

    ESC:清除当前命令行.F1: 单字符输出上次输入的命令 相当于方向键上的 → 的作用.F2: 可复制字符数量 , 输入上次命令中含有的字符,系统自动删除此字符后的内容.F3: 重新输入前一次输入的命 ...

  7. 据库都有哪些锁 然后 Kill session

    当某个数据库用户在数据库中插入.更新.删除一个表的数据,或者增加一个表的主键时或者表的索引时,常常会出现ora-00054:resource busy and acquire with nowait ...

  8. CentOS6配置国内yum源

    在安装完CentOS后为了加快安装.更新rpm包的速度.需要将yum源改为国内源,国内比较快的源有中科大.163.sohu源.下面修改为163源为例子: 首先进入源的配置目录:执行 cd /etc/y ...

  9. asp.net5 操作Cookie

    写入Cookie var CookieOption = new CookieOptions(); CookieOption.Path = "/"; //on localhost, ...

  10. Android中top命令字段含义

    PID       PR     CPU%      S       #THR           VSS        RSS       PCY           UID      Name 1 ...