什么是LDAP

LDAP 的全称是 Lightweight Directory Access Protocol,「轻量目录访问协议」

LDAP 「是一个协议」,约定了 Client 与 Server 之间的信息交互格式、使用的端口号、认证方式等内容。而 「LDAP 协议的实现」,有着众多版本,例如微软的 Active Directory 是 LDAP 在 Windows 上的实现,AD 实现了 LDAP 所需的树形数据库、具体如何解析请求数据并到数据库查询然后返回结果等功能。再例如 OpenLDAP 是可以运行在 Linux 上的 LDAP 协议的开源实现。而我们平常说的 LDAP Server,一般指的是安装并配置了 Active Directory、OpenLDAP 这些程序的服务器。

LDAP结构

属性 解释
dn(Distinguished Name) 一条记录的位置 ,如上图,我们要想描述baby这个节点,描述如下cn=baby,ou=marketing,ou=pepple,dc=mydomain,dc=org
dc(domain compoent) 一条记录所属区域 域名部分
ou (Organization Unit) 一条记录所属组织
cn/uid(Common Name) 一条记录的名字/ID
Entry 条目记录数

LDAP查询语法

search语法: attribute operator value
search filter options:( "&" or "|" (filter1) (filter2) (filter3) ...) ("!" (filter))

详细解释

=(等于)

查找”Name”属性为”John”的所有对象:

(Name=John)

这条语句会返回”name”为”john”的所有对象,以便强调LDAP语句的开始和结束

&(逻辑与)

如果具有多个条件,并且希望所有条件都能满足,则使用该语法。

(&(Name=John)(live=Dallas))

以上语句查询居住在Dallas,并且名为John的所有人员

!(逻辑非)

此操作符用来排除具有特定属性的对象:

(!Name=John)

查找所有”name”不为”John”的人员

通配符 *

可以用通配符表示值可以等于任何内容

(title=*)

查找具有职务头衔的所有人员

(Name=Jo*)

查找所有”Name”以”Jo”开头的人员

最后,举一个较复杂的例子:

(&(Name=John)(|(live=Dallas)(live=Austin)))

查找所有居住在Dallas或Austin,并且名为John的人员

SpringBoot集成LDAP并进行分页查询

添加Maven依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-ldap</artifactId>
  <version>2.0.4.RELEASE</version>
</dependency>

分页查询

public static void main(String[] args) {
  
  String ldapUserName = "xxxx";
  String ldapPassword = "xxxx";

  LdapContext ctx = null;
  Hashtable<String, String> HashEnv = new Hashtable<String, String>();
  HashEnv.put(Context.PROVIDER_URL, ldapUrl);
  // LDAP访问安全级别(none,simple,strong)
  HashEnv.put(Context.SECURITY_AUTHENTICATION, "simple");   
  //AD的用户名
  HashEnv.put(Context.SECURITY_PRINCIPAL, ldapUsername);
  //AD的密码    
  HashEnv.put(Context.SECURITY_CREDENTIALS, ldapPassword);  
  HashEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
  //连接超时设置为3秒
  HashEnv.put("com.sun.jndi.ldap.connect.timeout", "3000"); 
  int pageSize = 15;
  int currentPage = 0;
  int total = 0;
  try {
    // 初始化连接
    ctx = new InitialLdapContext(HashEnv, null);
    // 设置分页大小
    ctx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.CRITICAL)});
    // 查询过滤器
    String filter = "userprincipalname=*@*";
    SearchControls searchControls = new SearchControls();
    searchControls.setCountLimit(pageSize);
    // 设置查询该树和子树的数据
    searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    // 设置返回值
    String[] s = {"usncreated", "userprincipalname"};
    searchControls.setReturningAttributes(s);
    byte[] cookie = null;
    do {
      // 查询
      NamingEnumeration results = ctx.search("ou=软件开发,DC=TEST", filter, searchControls);
      while (results != null && results.hasMoreElements()) {
        SearchResult entry = (SearchResult) results.next();
        total++;
        if (currentPage == pageNo) {
          // *****需要返回的页面的数据在这里操作*****

        }
      }
      Control[] controls = ctx.getResponseControls();
      if (controls != null) {
        for (int i = 0; i < controls.length; i++) {
          if (controls[i] instanceof PagedResultsResponseControl) {
            PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
            cookie = prrc.getCookie();
          }
        }
      }
      // 将cookie信息设置进去,下次查询的时候会在本次查询的基础上向后查询,如果没有cookie了,就说明没有数据了
      ctx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, cookie, Control.CRITICAL)});
      currentPage++;
    } while (cookie != null);

  } catch (Exception e) {
    log.error("LDAP获取信息失败", e);
  } finally {
    if (null != ctx) {
      try {
        ctx.close();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}