`
mingo
  • 浏览: 40527 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

ACEGI结合LDAP进行统一用户管理

    博客分类:
  • Java
阅读更多
用acegi进行用户登陆和权限判断已有好几个项目的经验了,但是用户密码和权限信息都是存储在数据库里面的,各套系统之间的用户数据彼此都互相独立,这个系统一套用户名密码,那个系统则是另一套,每个用户要同时记住好几个密码,比较麻烦。但是现在的发展趋势都是用LDAP对用户进行统一管理,即在LDAP服务器中进行认证管理,在业务系统里进行授权管理。
这样子,只要各业务系统都练到这一个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表示可以在子节点中进行搜索。

大致配置就是这些了。
分享到:
评论
3 楼 mingo 2008-12-04  
DaoAuthoritiesPopulator不需要继承什么基类,只是实现了一个接口:
public class DaoAuthoritiesPopulator implements LdapAuthoritiesPopulator
2 楼 liaolei23@163.com 2008-08-29  
DaoAuthoritiesPopulator  需要继承什么类吗 ?????
1 楼 zhuchanglin 2008-07-22  
你好,这种方法确实可行。但是存在一个问题,我如果只用数据库存储信息的话,可以方便定义userDetailsService,这样,我就可以将用户的中文名、登录名、用户状态完整地传递给Acegi。但是现在由于使用LDAP验证,而这个时候,userDetails好像不能自己去给(或者我没有找到方法?),那么又如何让LDAP中的属性映射到UserDetail中的对应属性呢?

相关推荐

    JAVA上百实例源码以及开源项目源代码

    发送消息,同时对文本进行少量修改,发送end-of-messages消息,最后关闭连接。 Tcp服务端与客户端的JAVA实例源代码 2个目标文件 摘要:Java源码,文件操作,TCP,服务器  Tcp服务端与客户端的JAVA实例源代码,一个简单...

    JAVA上百实例源码以及开源项目

    发送消息,同时对文本进行少量修改,发送end-of-messages消息,最后关闭连接。 Tcp服务端与客户端的JAVA实例源代码 2个目标文件 摘要:Java源码,文件操作,TCP,服务器  Tcp服务端与客户端的JAVA实例源代码,一个简单...

    java开源包1

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包11

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包2

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包3

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包6

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包5

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包10

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包4

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包8

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包7

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包9

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    java开源包101

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

    Java资源包01

    它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JS...

Global site tag (gtag.js) - Google Analytics