LDAP开发

Java提供了JNDI库用于LDAP开发,Spring也提供了Spring-LDAP,用类似hibernateTemplate的原理,使得操作LDAP更加简便。
我们先来学习JNDI操作LDAP的方式:
package com.halo.ldap;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Hashtable;

// 以下是引用jndi相关类
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

public class LDAPExample {

    // LDAP服务器地址
    private final String URL = "ldap://127.0.0.1:389/";

    // 改成你的根域名
    private final String BASE_DN = "dc=halo,dc=rdc";

    // JNDI工厂类
    private final String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";

    // LDAP认证方式
    private final String AUTHENTICATION = "simple";

    // 改成你的LDAP管理员帐号
    private final String ADMINISTRATOR = "cn=admin,dc=halo,dc=rdc";

    // 改成你的管理员密码
    private final String PASSWORD = "password";

    private final Control[] connCtls = null;

    // LDAP上下文
    private LdapContext ctx = null;

    ...

    // 建立到LDAP服务器的连接
    public void connect() {
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
        env.put(Context.PROVIDER_URL, URL + BASE_DN);
        env.put(Context.SECURITY_AUTHENTICATION, AUTHENTICATION);
        env.put(Context.SECURITY_PRINCIPAL, ADMINISTRATOR);
        env.put(Context.SECURITY_CREDENTIALS, PASSWORD);

        try {
            ctx = new InitialLdapContext(env, connCtls);
            System.out.println("LDAP server is connected.");
        } catch (NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // 关闭到LDAP服务器的连接
    public void disconnect() {
        if (null != ctx) {
            try {
                ctx.close();
                System.out.println("LDAP server is disconnected.");
            } catch (NamingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    …

}

下面展示一个查询LDAP的entry的方法:

    /**
     * 根据DN(域名)查找一个entry
     * @param key DN的名称,例如uid、ou
     * @param value DN的值
     * @return 返回entry的所有属性(attribute)
     */
    public String getDN(String key, String value) {
        String dn = "";
        if (null == ctx) {
            dn = "Not connected yet!";
            return dn;
        }

        SearchControls constraints = new SearchControls();
        constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);

        try {
            NamingEnumeration<SearchResult> en = ctx.search("", key + "=" + value, constraints);

            while (en != null && en.hasMoreElements()) {
                SearchResult result = en.nextElement();
                dn += result.getName();
                dn += "," + BASE_DN;
                Attributes attrs = result.getAttributes();
                if (attrs != null) {
                    NamingEnumeration<? extends Attribute> nes = attrs.getAll();
                    while (nes.hasMore()) {
                        Attribute attr = nes.next();

                        dn += "\n" + attr.getID() + ": " + attr.get();
                    }
                }
            }
        } catch (NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return dn;
    }

下面展示一个添加LDAP的entry的方法:
    public void addPerson() {
        Attribute objectClass = new BasicAttribute("objectclass");
        String[] objectClassPersons = { "inetOrgPerson", "organizationalPerson", "person", "top" };
        Arrays.sort(objectClassPersons);
        for (String objectClassPerson : objectClassPersons) {
            objectClass.add(objectClassPerson);
        }

        Attributes attrs = new BasicAttributes(true);
        attrs.put(objectClass);

        String uid = "Fafa";
        attrs.put("uid", uid);
        attrs.put("cn", uid);
        attrs.put("sn", uid);
        attrs.put("displayName", "方方");
        attrs.put("mail", "[email protected]");
        attrs.put("description", "方方的登录帐号");
        try {
            attrs.put("userPassword", "password".getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        String userDN = "uid=" + uid + ",ou=People," + BASE_DN;
        if (null != ctx) {
            try {
                ctx.createSubcontext(userDN, attrs);
                System.out.println("Person added!");
            } catch (NamingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else {
            System.out.println("Not connected yet!");
        }

    }

可见用JNDI操作LDAP还是挺麻烦的,也不便于应用内部的解耦。鉴于此,Spring为我们提供了Spring-LDAP库,使得我们完全不必考虑创建LdapContext连接和关闭,循环NamingEnumeration以读取LDAP属性。我们来看一下使用Spring-LDAP操作的例子:
package com.halo.ldap.dao.impl;

import java.util.List;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;

// Spring-LDAP的相关包
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.stereotype.Repository;
import com.halo.ldap.dao.PeopleDao;
import com.halo.ldap.domain.People;

// 本实例结合了注解式的Spring MVC框架,我们可以把操作LDAP的类当作MVC框架的Dao对象
@Repository("peopleDao'")
public class PeopleDaoImpl implements PeopleDao {

    //  ldapTemplate对象采用类似hibernateTemplate对象的方式,在applicationContext.xml文件中定义,后面我们会帖出applicationContext.xml文件的例子
    @Autowired
    private LdapTemplate ldapTemplate;

    ...
}
我们来看几种查询entry的方法,以下是一个遍历查找所有 objectclass=organizationalUnit的entry的方法,方法返回entry的ou属性(attribute)名:
    @SuppressWarnings("unchecked")
    @Override
    public List<String> getAllUnits() {
        return ldapTemplate.search("", "(objectclass=organizationalUnit)", new AttributesMapper() {
            public Object mapFromAttributes(Attributes attrs) throws javax.naming.NamingException {
                return attrs.get("ou").get();
            }
        });
    }
可见用Spring-LDAP查询和操作LDAP的方法要简单很多,完全不必考虑连接LDAP和关闭到LDAP的连接。
以下是一个遍历查找所有 objectclass=person的entry的方法,方法返回Person的对象:
    @SuppressWarnings("unchecked")
    @Override
    public List<People> getAllPeople() {
        return ldapTemplate.search("", "(objectclass=person)", new AttributesMapper() {

            @Override
            public Object mapFromAttributes(Attributes attrs) throws NamingException {
                People people = new People();
                people.setCn(attrs.get("cn") == null ? null : (String) attrs.get("cn").get());
                people.setSn(attrs.get("sn") == null ? null : (String) attrs.get("sn").get());
                people.setDescription(
                        attrs.get("description") == null ? null : (String) attrs.get("description").get());
                people.setPhone(attrs.get("phone") == null ? null : (String) attrs.get("phone").get());

                return people;
            }
        });
    }
以下是一个根据DN(域名)精确查找entry的方法
    @Override
    public People findPeople(String dn) {
        return (People) ldapTemplate.lookup(dn, new AttributesMapper() {
            @Override
            public Object mapFromAttributes(Attributes attrs) throws NamingException {
                People people = new People();
                people.setCn(attrs.get("cn") == null ? null : (String) attrs.get("cn").get());
                people.setSn(attrs.get("sn") == null ? null : (String) attrs.get("sn").get());
                people.setDescription(
                        attrs.get("description") == null ? null : (String) attrs.get("description").get());
                people.setPhone(attrs.get("phone") == null ? null : (String) attrs.get("phone").get());

                return people;
            }

        });
    }
Spring-LDAP配置LDAP连接参数的方式也和Spring + Hibernate的配置方式非常相似,都是在applicationContext.xml文件中配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 与JNDI的参数一样 -->
    <bean id="ldapSource" class="org.springframework.ldap.core.support.LdapContextSource">
        <property name="url" value="ldap://127.0.0.1:389/" />
        <property name="base" value="dc=halo,dc=rdc" />
        <property name="userDn" value="cn=admin,dc=halo,dc=rdc" />
        <property name="password" value="password" />
    </bean>
    <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
        <constructor-arg ref="ldapSource" />
    </bean>
</beans>
注意配置了applicationContext.xml上下文后,就要在web.xml中配置listener来加载:
    <!-- Spring上下文配置 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
Spring-LDAP的jar包在这里下载:http://download.csdn.net/detail/u013668719/9412156
按照Spring-ldap官方网站的说法,还需要在项目中加入以下jar包:
spring-core (miscellaneous utility classes used internally by the framework)
spring-beans (contains interfaces and classes for manipulating Java beans)
commons-logging (a simple logging facade, used internally)
commons-lang (misc utilities, used internally)
以上是jar包的名称,实际jar文件名中还有版本号,例如spring-core的jar文件名是“spring-core-3.2.9.RELEASE.jar”。

你可能感兴趣的:(开发,LDAP,spring-ldap)