如果对于这系列文章有疑问,可以先阅读以下链接内容(含Demo及源码下载):
Spring Security入门篇——搭建简易权限框架:
http://www.javali.org/archive/getting-start-spring-security.html
Spring Security入门篇——集成DB认证:
http://www.javali.org/archive/getting-start-spring-security-integrate-db.html
Spring security进阶——扩展UserDetails:
http://www.javali.org/archive/spring-security-advanced-extend-userdetails.html
Spring security进阶——资源汉化(i18n):
http://www.javali.org/archive/spring-security-advanced-i18n.html
进入主题前,需要从以上链接中下载Demo工程,Spring Security提供了良好的LDAP扩展方式,基于简单的配置即可集成到你的应用里
在simpleDemo项目pom.xml的基础上引入:
1. <dependency>
2. <groupId>org.springframework.security</groupId>
3. <artifactId>spring-security-ldap</artifactId>
4. 3.0.5.RELEASE</version>
5. <type>jar</type>
6. <scope>compile</scope>
7. </dependency>
但是集成方式取决于LDAP存储的数据及业务系统需求,需要分两种情况考虑:
1,LDAP服务器中存有帐号信息和角色信息
2,LDAP服务器只存了帐号信息
大多场合都属于后者,因为角色是由业务系统需求决定的,而LDAP在企业仅作为用户信息存储的一种方案,下面就这两种情况来看SS是怎样集成LDAP认证的
第一种情况:
LDAP上已经存有用户帐号及角色信息,我们只需要根据SS提供的对外接口,配置上相应的参数就行了,用户密码验证,获取角色等交给SS的LDAP扩展模块自己完成,将
覆盖SimpleDemo中的security.xml配置文件即可,建议用
了解LDAP数据的内部结构后再替换红色字体部分
1. <ldap-server
2. "myLdap"
3. "389"
4. "ldap://ldap.javali.org:389/dc=javali,dc=org"
5. "manager@javali.org"
6. "*******"
7. <authentication-manager>
8. <ldap-authentication-provider
9. "myLdap"
10. "(accountName={0})"
11. "OU=Users,OU=DEPARTMENT"
12. "OU=Groups"
13. "cn"
14. "(member={0})"
15. "ROLE_">
16. </ldap-authentication-provider>
17. </authentication-manager>
第二种情况:
比第一种情况复杂很多,既然角色由业务系统需求决定,角色信息就保存在业务系统的数据库;处理流程应该是:LDAP负责密码认证,然后在SS-
LDAP基础上做扩展,从DB中加载用户角色,思路是正确的,但如何扩展,如何实现,困扰了我很长时间;最后多亏了snowolf的鼎力支持(暗自庆幸身
边有spring大牛真好)
我们在阅读ss集成ldap源码时发现了DefaultLdapAuthoritiesPopulator类,它有一个方法签名
1. protected
2.
3. 我想你看到方法名就应该知道它的作用了,我们就可以写一个类继承DefaultLdapAuthoritiesPopulator,在getAdditionalRoles方法里加上从数据库获取username的角色列表代码就完事了,代码如下
4. public class MyLdapAuthoritiesPopulator extends
5. public
6. String groupSearchBase) {
7. super(contextSource, groupSearchBase);
8. }
9. protected
10. DirContextOperations user, String username) {
11. // 授权集合
12. new
13. // 根据username读取用户信息
14.
15. //TODO 根据用户信息从DB取得用户角色列表
16. //将角色添加到集合里即可
17. new GrantedAuthorityImpl("");
18. authorites.add(authority);
19. return
20. }
21. }
此种场景只能采用Bean的配置方式 :
1. <beans:bean
2. "contextSource"
3. class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
4. <beans:constructor-arg
5. "ldap://ldap.javali.org:389/dc=javali,dc=org"
6. <beans:property
7. "userDn"
8. "manager@javali.org"
9. <beans:property
10. "password"
11. "******"
12. </beans:bean>
13. <beans:bean
14. "ldapAuthProvider"
15. class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
16. <beans:constructor-arg>
17. <beans:bean
18. class="org.springframework.security.ldap.authentication.BindAuthenticator">
19. <beans:constructor-arg
20. "contextSource"
21. <beans:property
22. "userSearch">
23. <beans:bean
24. class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
25. <beans:constructor-arg
26. "dc=javali,dc=org"
27. <beans:constructor-arg
28. "(sAMAccountName={0})"
29. <beans:constructor-arg
30. "contextSource"
31. </beans:bean>
32. </beans:property>
33. </beans:bean>
34. </beans:constructor-arg>
35. <beans:constructor-arg>
36. <beans:bean
37. "ldapAuthoritiesPopulator"
38. class="org.javali.security.ext.MyLdapAuthoritiesPopulator">
39. <beans:constructor-arg
40. "contextSource"
41. <beans:constructor-arg
42. "ou=Groups,dc=javali,dc=org"
43. </beans:bean>
44. </beans:constructor-arg>
45. <beans:property
46. "userDetailsContextMapper">
47. <beans:bean
48. "ldapUserDetailsMapper"
49. class="org.springframework.security.ldap.userdetails.LdapUserDetailsMapper">
50. <beans:property
51. "rolePrefix"
52. "ROLE_"
53. <beans:property
54. "convertToUpperCase"
55. "true"
56. </beans:bean>
57. </beans:property>
58. </beans:bean>
59. <authentication-manager>
60. <authentication-provider
61. "ldapAuthProvider">
62. </authentication-provider>
63. </authentication-manager>
在配置 BindAuthenticator类时查询用户可有两种方式(可参见它的父类AbstractLdapAuthenticator),一种是
userDnFormat,另一种是LdapUserSearch,我们采用的是第二种,使用第一种配置的时候发现它只能查找当前userDn目录下用
户,如果有用户在更深层次就没法做到了,LdapUserSearch可以支持基于目录模糊匹配的查询方式,更强大,至少满足了我的ldap用户查询

















