最近利用空闲时间研究了一把LDAP,然后用spring进行了一些编程尝试,通过spring的LdapTemplate可以很方便的进行LDAP的CRUD操作。如果你不清楚啥是LDAP的话,可以查询相关资料后再看此文。一般来说LDAP可以用来作为一个用户中心,围绕LDAP可以部署一些应用来共享相同的账号,这个在企业管理中是非常有帮助的,因为企业的内部应用可能是几个到几十个,员工如果有统一的账号密码,那将非常方便。
我也是因为内部需要,围绕LDAP做了一些应用集成,使用的LDAP服务器是apache的DS,标准的LDAP协议,客户端编程用java,使用spring的LdapTemplate类进行操作。使用maven管理的话,在项目中加入如下依赖:
-
<dependency>
-
<groupId>com.sun </groupId>
-
<artifactId>ldapbp </artifactId>
-
<version>1.0 </version>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework </groupId>
-
<artifactId>spring-ldap </artifactId>
-
<version>1.1.2 </version>
-
</dependency>
然后就可以使用LDAP进行操作了,当然了也要加入其它的spring对应的包,比如core包等,下面分别说明使用spring的LdapTemplate如何进行操作。注意,在应用之前请先配置好apache-DS服务(请参考文章xxx)。
1、初始化LdapTemplate
-
private static final LdapTemplate template ;
-
-
static {
-
LdapContextSource cs = new LdapContextSource ( ) ;
-
cs. setCacheEnvironmentProperties ( false ) ;
-
cs. setUrl ( "ldap://192.168.1.188:10389" ) ;
-
cs. setBase ( "dc=mzone,dc=cc" ) ;
-
cs. setAuthenticationSource ( new AuthenticationSource ( ) {
-
@Override
-
public String getCredentials ( ) {
-
return "mzonecc" ;
-
}
-
-
@Override
-
public String getPrincipal ( ) {
-
return "uid=admin,ou=system" ;
-
}
-
} ) ;
-
template = new LdapTemplate (cs ) ;
-
}
初始化时主要是设置连接地址、基础目录(我们这里是dc=mzone,dc=cc)和认证信息(包括账号和密码)。注意认证信息中getCredentials返回的是密码信息,而getPrincipal方法返回的是账号DN(基于基础目录)。
2、查询(搜索)
查询在LdapTemplate中是search说法,相关代码如下:
-
public User getUserById ( String uid ) {
-
String filter = "(&(objectclass=inetOrgPerson)(uid=" + uid + "))" ;
-
List <User > list = template. search ( "ou=rd", filter, new AttributesMapper ( ) {
-
@Override
-
public Object mapFromAttributes ( Attributes attributes ) throws NamingException {
-
User user = new User ( ) ;
-
-
Attribute a = attributes. get ( "cn" ) ;
-
if (a != null ) user. setRealname ( ( String )a. get ( ) ) ;
-
-
a = attributes. get ( "uid" ) ;
-
if (a != null ) user. setUsername ( ( String )a. get ( ) ) ;
-
-
return user ;
-
}
-
} ) ;
-
if (list. isEmpty ( ) ) return null ;
-
return list. get ( 0 ) ;
-
}
首先我们要构造一个filter,即search方法的第2个参数,这个filter是标准的LDAP查询过滤器,可以参考下LDAP的filter写法相关文档。
3、添加
-
public boolean addUser (User vo ) {
-
try {
-
// 基类设置
-
BasicAttribute ocattr = new BasicAttribute ( "objectClass" ) ;
-
ocattr. add ( "top" ) ;
-
ocattr. add ( "person" ) ;
-
ocattr. add ( "uidObject" ) ;
-
ocattr. add ( "inetOrgPerson" ) ;
-
ocattr. add ( "organizationalPerson" ) ;
-
// 用户属性
-
Attributes attrs = new BasicAttributes ( ) ;
-
attrs. put (ocattr ) ;
-
attrs. put ( "cn", StringUtils. trimToEmpty (vo. getRealname ( ) ) ) ;
-
attrs. put ( "sn", StringUtils. trimToEmpty (vo. getUsername ( ) ) ) ;
-
attrs. put ( "displayName", StringUtils. trimToEmpty (vo. getRealname ( ) ) ) ;
-
attrs. put ( "mail", StringUtils. trimToEmpty (vo. getEmail ( ) ) ) ;
-
attrs. put ( "telephoneNumber", StringUtils. trimToEmpty (vo. getMobile ( ) ) ) ;
-
attrs. put ( "title", StringUtils. trimToEmpty (vo. getTitle ( ) ) ) ;
-
attrs. put ( "userPassword", StringUtils. trimToEmpty (vo. getPassword ( ) ) ) ;
-
template. bind ( "uid=" + vo. getUsername ( ). trim ( ), null, attrs ) ;
-
return true ;
-
} catch ( Exception ex ) {
-
ex. printStackTrace ( ) ;
-
return false ;
-
}
-
}
在LDAP中是没有添加这一说法的,标准的叫法是绑定,对应的删除就是解绑。绑定时要将所有必须属性都添加上,首先是objectClass属性,这个是LDAP中的对象,LDAP中的对象是继承的,每个对象都有一些特定的属性,有些属性是必须的,有些是可选的。第2个步骤就是将每个对象的必须属性和你想要的非必须属性填上交由LdapTemplate进行绑定即可。
4、更新
-
public boolean updateUser (User vo ) {
-
try {
-
template. modifyAttributes ( "uid=" + vo. getUsername ( ). trim ( ), new ModificationItem [ ] {
-
new ModificationItem ( DirContext. REPLACE_ATTRIBUTE, new BasicAttribute ( "cn", vo. getRealname ( ). trim ( ) ) ),
-
new ModificationItem ( DirContext. REPLACE_ATTRIBUTE, new BasicAttribute ( "displayName", vo. getRealname ( ). trim ( ) ) ),
-
new ModificationItem ( DirContext. REPLACE_ATTRIBUTE, new BasicAttribute ( "sn", vo. getUsername ( ). trim ( ) ) ),
-
new ModificationItem ( DirContext. REPLACE_ATTRIBUTE, new BasicAttribute ( "mail", vo. getEmail ( ). trim ( ) ) ),
-
new ModificationItem ( DirContext. REPLACE_ATTRIBUTE, new BasicAttribute ( "telephoneNumber", vo. getMobile ( ). trim ( ) ) ),
-
new ModificationItem ( DirContext. REPLACE_ATTRIBUTE, new BasicAttribute ( "title", vo. getTitle ( ). trim ( ) ) )
-
} ) ;
-
return true ;
-
} catch ( Exception ex ) {
-
ex. printStackTrace ( ) ;
-
return false ;
-
}
-
}
更新就是替换属性,使用ModificationItem类进行处理。
5、删除
-
public boolean deleteUser ( String username ) {
-
try {
-
template. unbind ( "uid=" + username. trim ( ) ) ;
-
return true ;
-
} catch ( Exception ex ) {
-
ex. printStackTrace ( ) ;
-
return false ;
-
}
-
}
删除也就是解绑的过程,直接调用unbind即可。