如果对于这系列文章有疑问,可以先阅读以下链接内容(含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的基础上引入:
但是集成方式取决于LDAP存储的数据及业务系统需求,需要分两种情况考虑:
1,LDAP服务器中存有帐号信息和角色信息
2,LDAP服务器只存了帐号信息
大多场合都属于后者,因为角色是由业务系统需求决定的,而LDAP在企业仅作为用户信息存储的一种方案,下面就这两种情况来看SS是怎样集成LDAP认证的
第一种情况:
LDAP上已经存有用户帐号及角色信息,我们只需要根据SS提供的对外接口,配置上相应的参数就行了,用户密码验证,获取角色等交给SS的LDAP扩展模块自己完成,将 security_ldap1
覆盖SimpleDemo中的security.xml配置文件即可,建议用 Apache Directory Studio
了解LDAP数据的内部结构后再替换红色字体部分
第二种情况:
比第一种情况复杂很多,既然角色由业务系统需求决定,角色信息就保存在业务系统的数据库;处理流程应该是:LDAP负责密码认证,然后在SS-
LDAP基础上做扩展,从DB中加载用户角色,思路是正确的,但如何扩展,如何实现,困扰了我很长时间;最后多亏了snowolf的鼎力支持(暗自庆幸身
边有spring大牛真好)
我们在阅读ss集成ldap源码时发现了DefaultLdapAuthoritiesPopulator类,它有一个方法签名
此种场景只能采用Bean的配置方式 : security_ldap2
在配置 BindAuthenticator类时查询用户可有两种方式(可参见它的父类AbstractLdapAuthenticator),一种是
userDnFormat,另一种是LdapUserSearch,我们采用的是第二种,使用第一种配置的时候发现它只能查找当前userDn目录下用
户,如果有用户在更深层次就没法做到了,LdapUserSearch可以支持基于目录模糊匹配的查询方式,更强大,至少满足了我的ldap用户查询
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的基础上引入:
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-ldap</artifactId>
- <version>3.0.5.RELEASE</version>
- <type>jar</type>
- <scope>compile</scope>
- </dependency>
但是集成方式取决于LDAP存储的数据及业务系统需求,需要分两种情况考虑:
1,LDAP服务器中存有帐号信息和角色信息
2,LDAP服务器只存了帐号信息
大多场合都属于后者,因为角色是由业务系统需求决定的,而LDAP在企业仅作为用户信息存储的一种方案,下面就这两种情况来看SS是怎样集成LDAP认证的
第一种情况:
LDAP上已经存有用户帐号及角色信息,我们只需要根据SS提供的对外接口,配置上相应的参数就行了,用户密码验证,获取角色等交给SS的LDAP扩展模块自己完成,将 security_ldap1
覆盖SimpleDemo中的security.xml配置文件即可,建议用 Apache Directory Studio
了解LDAP数据的内部结构后再替换红色字体部分
- <ldap-server
- id="myLdap"
- port="389"
- url="ldap://ldap.javali.org:389/dc=javali,dc=org" #LDAP服务地址
- manager-dn="manager@javali.org" #提供一个有权限访问ldap服务的帐号
- manager-password="*******" />
- <authentication-manager>
- <ldap-authentication-provider
- server-ref="myLdap"
- user-search-filter="(accountName={0})" #ldap目录中存帐号名的节点名称
- user-search-base="OU=Users,OU=DEPARTMENT" #用户查找base
- group-search-base="OU=Groups"
- group-role-attribute="cn"
- group-search-filter="(member={0})" #用户所属角色的节点名称
- role-prefix="ROLE_">
- </ldap-authentication-provider>
- </authentication-manager>
第二种情况:
比第一种情况复杂很多,既然角色由业务系统需求决定,角色信息就保存在业务系统的数据库;处理流程应该是:LDAP负责密码认证,然后在SS-
LDAP基础上做扩展,从DB中加载用户角色,思路是正确的,但如何扩展,如何实现,困扰了我很长时间;最后多亏了snowolf的鼎力支持(暗自庆幸身
边有spring大牛真好)
我们在阅读ss集成ldap源码时发现了DefaultLdapAuthoritiesPopulator类,它有一个方法签名
- protected Set getAdditionalRoles(DirContextOperations user, String username)
- 我想你看到方法名就应该知道它的作用了,我们就可以写一个类继承DefaultLdapAuthoritiesPopulator,在getAdditionalRoles方法里加上从数据库获取username的角色列表代码就完事了,代码如下
- public class MyLdapAuthoritiesPopulator extends DefaultLdapAuthoritiesPopulator {
- public MyLdapAuthoritiesPopulator(ContextSource contextSource,
- String groupSearchBase) {
- super(contextSource, groupSearchBase);
- }
- protected Set<GrantedAuthority> getAdditionalRoles(
- DirContextOperations user, String username) {
- // 授权集合
- Set<GrantedAuthority> authorites = new HashSet<GrantedAuthority>();
- // 根据username读取用户信息
- //TODO 根据用户信息从DB取得用户角色列表
- //将角色添加到集合里即可
- GrantedAuthority authority = new GrantedAuthorityImpl("");
- authorites.add(authority);
- return authorites;
- }
- }
此种场景只能采用Bean的配置方式 : security_ldap2
- <beans:bean
- id="contextSource"
- class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
- <beans:constructor-arg
- value="ldap://ldap.javali.org:389/dc=javali,dc=org" />
- <beans:property
- name="userDn"
- value="manager@javali.org" />
- <beans:property
- name="password"
- value="******" />
- </beans:bean>
- <beans:bean
- id="ldapAuthProvider"
- class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
- <beans:constructor-arg>
- <beans:bean
- class="org.springframework.security.ldap.authentication.BindAuthenticator">
- <beans:constructor-arg
- ref="contextSource" />
- <beans:property
- name="userSearch">
- <beans:bean
- class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
- <beans:constructor-arg
- value="dc=javali,dc=org" />
- <beans:constructor-arg
- value="(sAMAccountName={0})" />
- <beans:constructor-arg
- ref="contextSource" />
- </beans:bean>
- </beans:property>
- </beans:bean>
- </beans:constructor-arg>
- <beans:constructor-arg>
- <beans:bean
- id="ldapAuthoritiesPopulator"
- class="org.javali.security.ext.MyLdapAuthoritiesPopulator">
- <beans:constructor-arg
- ref="contextSource" />
- <beans:constructor-arg
- value="ou=Groups,dc=javali,dc=org" />
- </beans:bean>
- </beans:constructor-arg>
- <beans:property
- name="userDetailsContextMapper">
- <beans:bean
- id="ldapUserDetailsMapper"
- class="org.springframework.security.ldap.userdetails.LdapUserDetailsMapper">
- <beans:property
- name="rolePrefix"
- value="ROLE_" />
- <beans:property
- name="convertToUpperCase"
- value="true" />
- </beans:bean>
- </beans:property>
- </beans:bean>
- <authentication-manager>
- <authentication-provider
- ref="ldapAuthProvider">
- </authentication-provider>
- </authentication-manager>
在配置 BindAuthenticator类时查询用户可有两种方式(可参见它的父类AbstractLdapAuthenticator),一种是
userDnFormat,另一种是LdapUserSearch,我们采用的是第二种,使用第一种配置的时候发现它只能查找当前userDn目录下用
户,如果有用户在更深层次就没法做到了,LdapUserSearch可以支持基于目录模糊匹配的查询方式,更强大,至少满足了我的ldap用户查询