用acegi进行用户登陆和权限判断已有好几个项目的经验了,但是用户密码和权限信息都是存储在数据库里面的,各套系统之间的用户数据彼此都互相独立,这个系统一套用户名密码,那个系统则是另一套,每个用户要同时记住好几个密码,比较麻烦。但是现在的发展趋势都是用LDAP对用户进行统一管理,即在LDAP服务器中进行认证管理,在业务系统里进行授权管理。
这样子,只要各业务系统都练到这一个LDAP服务器上,大家的账号和密码就都是统一的。
以下是acegi与Windows AD进行结合,实现用户统一管理的例子。
实现的思路是,在LDAP进行用户认证,在数据库中进行权限鉴别。
acegi也有针对LDAP进行认证和鉴权的全部代码和推荐配置,但是比较单纯,要么是全部数据库,要么是全部LDAP,对于LDAP+DB,还没有看到网上有例子,只有一个台湾的家伙,还觉得满保密,不想公开他的代码。
Windows AD,就是Windows Active Directory,是微软的域控制器,与windows操作系统进行了集成,支持LDAP协议。
1、将daoAuthenticationProvider换成ldapAuthenticationProvider
2、添加ldapAuthenticationProvider的bean定义:
3、添加authenticator的bean定义
其中userDnPatterns是根据不同的LDAP服务有着不同的配置,sAMAccountName是AD中存储用户账号的字段名称,后面那一串是账号路径的一部分。
4、编写自己的DaoAuthoritiesPopulator,从数据库中查询权限,这里有两个参数:数据源和查询SQL,数据源可以直接利用已经定义的dataSource,查询SQL就是以前在jdbcDaoImpl中用过的authoritiesByUsernameQuery。类中的代码如下(省去了dataSource和authoritiesByUsernameQuery的setter和getter):
bean定义XML文件如下:
5、添加LDAP服务器上下文的bean配置:
这样定义以后,大概相当于指定了进行用户认证的数据库schema。
在这里,推荐一个LDAP的浏览工具,叫LDAP Browser,下载地址是 http://file1.softsea.net/30190/ldapbrowser25ce.zip,可以用这个工具来判断你所拿到的上面三个参数的值是否正确。
6、添加userSearch的bean定义:
第一个构造参数表示搜索路径(指定了用户认证的数据表),第二个构造参数表示用怎么的查询条件去搜索,第三个构造参数是要搜索的上下文环境(指定了用户认证的数据库schema),,属性searchSubtree为true表示可以在子节点中进行搜索。
大致配置就是这些了。
这样子,只要各业务系统都练到这一个LDAP服务器上,大家的账号和密码就都是统一的。
以下是acegi与Windows AD进行结合,实现用户统一管理的例子。
实现的思路是,在LDAP进行用户认证,在数据库中进行权限鉴别。
acegi也有针对LDAP进行认证和鉴权的全部代码和推荐配置,但是比较单纯,要么是全部数据库,要么是全部LDAP,对于LDAP+DB,还没有看到网上有例子,只有一个台湾的家伙,还觉得满保密,不想公开他的代码。
Windows AD,就是Windows Active Directory,是微软的域控制器,与windows操作系统进行了集成,支持LDAP协议。
1、将daoAuthenticationProvider换成ldapAuthenticationProvider
- <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
- <property name="providers">
- <list>
- <ref local="ldapAuthenticationProvider"/>
- </list>
- </property>
- <property name="sessionController">
- <ref bean="concurrentSessionController"/>
- </property>
- </bean>
2、添加ldapAuthenticationProvider的bean定义:
- <!--
- LDAP+DB进行登陆判断
- LDAP中进行用户名认证(authenticator)
- DB中进行权限判断(daoPopulator)
- -->
- <bean id="ldapAuthenticationProvider" class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">
- <constructor-arg><ref local="authenticator"/></constructor-arg>
- <constructor-arg><ref local="daoPopulator"/></constructor-arg>
- <property name="userCache" ref="userCache"/>
- </bean>
3、添加authenticator的bean定义
- <!--
- 在LDAP Server中判断用户和密码的有效性
- initialDirContextFactory:LDAP上下文环境
- userDnPatterns:用户匹配模式,其中sAMAccountName是AD中用户名的字段名称
- -->
- <bean id="authenticator" class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
- <constructor-arg><ref local="initialDirContextFactory"/></constructor-arg>
- <property name="userDnPatterns">
- <list>
- <value>sAMAccountName={0},ou=BroadText_SH,DC=broadtext,DC=local</value>
- </list>
- </property>
- <property name="userSearch"><ref local="userSearch"/></property>
- </bean>
其中userDnPatterns是根据不同的LDAP服务有着不同的配置,sAMAccountName是AD中存储用户账号的字段名称,后面那一串是账号路径的一部分。
4、编写自己的DaoAuthoritiesPopulator,从数据库中查询权限,这里有两个参数:数据源和查询SQL,数据源可以直接利用已经定义的dataSource,查询SQL就是以前在jdbcDaoImpl中用过的authoritiesByUsernameQuery。类中的代码如下(省去了dataSource和authoritiesByUsernameQuery的setter和getter):
- private static final Log logger = LogFactory.getLog(DaoAuthoritiesPopulator.class);
- protected MappingSqlQuery authoritiesByUsernameMapping;
- private String authoritiesByUsernameQuery;
- private String rolePrefix = "";
- private DataSource dataSource;
- /* (non-Javadoc)
- * @see org.acegisecurity.providers.ldap.LdapAuthoritiesPopulator#getGrantedAuthorities(org.acegisecurity.userdetails.ldap.LdapUserDetails)
- */
- public GrantedAuthority[] getGrantedAuthorities(LdapUserDetails user){
- this.authoritiesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());
- List dbAuths = authoritiesByUsernameMapping.execute(user.getUsername());
- if (dbAuths.size() == 0) {
- throw new PermissionNotEnoughException("User has no GrantedAuthority");
- }
- GrantedAuthority[] arrayAuths = (GrantedAuthority[]) dbAuths.toArray(new GrantedAuthority[dbAuths.size()]);
- if (logger.isDebugEnabled()) {
- logger.debug("Getting authorities for user " + user.getUsername());
- logger.debug("授权成功 :" + user.getUsername());
- }
- return arrayAuths;
- }
- /**
- * Query object to look up a user's authorities.
- */
- protected class AuthoritiesByUsernameMapping extends MappingSqlQuery {
- protected AuthoritiesByUsernameMapping(DataSource ds) {
- super(ds, authoritiesByUsernameQuery);
- declareParameter(new SqlParameter(Types.VARCHAR));
- compile();
- }
- protected Object mapRow(ResultSet rs, int rownum)
- throws SQLException {
- String roleName = rolePrefix + rs.getString(2);
- GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
- return authority;
- }
- }
bean定义XML文件如下:
- <!--
- 从数据库中获取权限
- dataSource:数据源
- authoritiesByUsernameQuery:根据用户名查询权限的sql
- -->
- <bean id="daoPopulator" class="com.broadtext.eim.security.ldap.DaoAuthoritiesPopulator">
- <property name="dataSource" ref="dataSource"/>
- <property name="authoritiesByUsernameQuery">
- <value>select u.username,p.name from sys_user u,sys_role r,sys_permission p,sys_user_role ur,sys_role_permis rp where u.id=ur.user_id and r.id=ur.role_id and p.id=rp.permission_id and
- r.id=rp.role_id and p.open_flag='1' and u.username=?</value>
- </property>
- </bean>
5、添加LDAP服务器上下文的bean配置:
- <!--
- LDAP Server的配置信息
- 构造函数的参数:LDAP服务器地址和端口
- managerDn:管理员账号在LDAP中的地址
- managerPassword:管理员密码
- -->
- <bean id="initialDirContextFactory" class="org.acegisecurity.ldap.DefaultInitialDirContextFactory">
- <constructor-arg value="ldap://你的LDAP服务器地址:端口"/>
- <property name="managerDn"><value>yourAdministratorName</value></property>
- <property name="managerPassword"><value>yourAdministratorPassword</value></property>
- </bean>
这样定义以后,大概相当于指定了进行用户认证的数据库schema。
在这里,推荐一个LDAP的浏览工具,叫LDAP Browser,下载地址是 http://file1.softsea.net/30190/ldapbrowser25ce.zip,可以用这个工具来判断你所拿到的上面三个参数的值是否正确。
6、添加userSearch的bean定义:
- <!--
- 在LDAP服务器校验账号的时候,定义搜索账号的规则
- -->
- <bean id="userSearch" class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">
- <constructor-arg>
- <value>ou=BroadText_SH,DC=broadtext,DC=local</value>
- </constructor-arg>
- <constructor-arg>
- <value>(sAMAccountName={0})</value>
- </constructor-arg>
- <constructor-arg>
- <ref local="initialDirContextFactory"/>
- </constructor-arg>
- <property name="searchSubtree">
- <value>true</value>
- </property>
- </bean>
第一个构造参数表示搜索路径(指定了用户认证的数据表),第二个构造参数表示用怎么的查询条件去搜索,第三个构造参数是要搜索的上下文环境(指定了用户认证的数据库schema),,属性searchSubtree为true表示可以在子节点中进行搜索。
大致配置就是这些了。