基本用法

使用AttributesMapper进行搜索和查找

以下示例使用AttributesMapper来构建所有人员对象的通用名称列表。

示例1. 返回单个属性的AttributesMapper
import static org.springframework.ldap.query.LdapQueryBuilder.query;

public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;

   public void setLdapClient(LdapClient ldapClient) {
      this.ldapClient = ldapClient;
   }

   public List<String> getAllPersonNames() {
      return ldapClient.search()
                .query(query().where("objectclass").is("person"))
                .toList((Attributes attrs) -> (String) attrs.get("cn").get());
   }
}

AttributesMapper的内联实现从Attributes对象获取所需的属性值并返回它。在内部,LdapClient遍历所有找到的条目,为每个条目调用给定的AttributesMapper,并将结果收集到一个列表中。然后,该列表由search方法返回。

请注意,AttributesMapper实现可以很容易地修改为返回一个完整的Person对象,如下所示

示例2. 返回一个Person对象的AttributesMapper
import static org.springframework.ldap.query.LdapQueryBuilder.query;

public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   private class PersonAttributesMapper implements AttributesMapper<Person> {
      public Person mapFromAttributes(Attributes attrs) throws NamingException {
         Person person = new Person();
         person.setFullName((String)attrs.get("cn").get());
         person.setLastName((String)attrs.get("sn").get());
         person.setDescription((String)attrs.get("description").get());
         return person;
      }
   }

   public List<Person> getAllPersons() {
      return ldapClient.search()
            .query(query().where("objectclass").is("person"))
            .toList(new PersonAttributesMapper());
   }
}

LDAP中的条目通过其判别名(DN)唯一标识。如果您有条目的DN,您可以直接检索该条目而无需查询。这在Java LDAP中称为“查找”。以下示例显示了Person对象的查找

示例3. 查找Person对象
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public Person findPerson(String dn) {
      return ldapClient.search().name(dn).toObject(new PersonAttributesMapper());
   }
}

前面的示例查找指定的DN,并将找到的属性传递给提供的AttributesMapper——在本例中,结果是一个Person对象。

构建LDAP查询

LDAP搜索涉及许多参数,包括以下内容

  • 基本LDAP路径:搜索应从LDAP树中的何处开始。

  • 搜索范围:搜索应在LDAP树中深入到何处。

  • 要返回的属性。

  • 搜索过滤器:在选择范围内的元素时要使用的标准。

Spring LDAP提供了一个LdapQueryBuilder,它具有用于构建LDAP查询的流式API。

假设您要执行从基本DN dc=261consulting,dc=com开始的搜索,将返回的属性限制为cnsn,过滤器为(&(objectclass=person)(sn=?)),其中我们希望将?替换为lastName参数的值。以下示例显示了如何使用LdapQueryBuilder来完成此操作

示例4. 动态构建搜索过滤器
import static org.springframework.ldap.query.LdapQueryBuilder.query;

public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public List<String> getPersonNamesByLastName(String lastName) {

      LdapQuery query = query()
         .base("dc=261consulting,dc=com")
         .attributes("cn", "sn")
         .where("objectclass").is("person")
         .and("sn").is(lastName);

      return ldapClient.search().query(query)
            .toObject((Attributes attrs) -> (String) attrs.get("cn").get());
   }
}
除了简化复杂搜索参数的构建之外,LdapQueryBuilder及其相关类还提供了对搜索过滤器中任何不安全字符的正确转义。这可以防止“LDAP注入”,即用户可能会使用此类字符将不需要的操作注入到您的LDAP操作中。
LdapClient包含许多重载方法用于执行LDAP搜索。这是为了适应尽可能多的不同用例和编程风格偏好。对于绝大多数用例,建议使用接受LdapQuery作为输入的方法。
AttributesMapper只是在处理搜索和查找数据时可以使用的回调接口之一。有关替代方案,请参阅使用DirContextAdapter简化属性访问和操作

有关LdapQueryBuilder的更多信息,请参阅高级LDAP查询

动态构建判别名

判别名(LdapName)的标准Java实现,在解析判别名方面表现良好。然而,在实际使用中,此实现存在一些缺点

  • LdapName实现是可变的,这对于表示身份的对象来说非常不合适。

  • 尽管其可变性,但使用LdapName动态构建或修改判别名的API很笨拙。提取索引或(特别是)命名组件的值也有些尴尬。

  • LdapName上的许多操作都会抛出检查异常,这需要try-catch语句来处理错误通常是致命的且无法以有意义的方式修复的情况。

为了简化判别名的处理,Spring LDAP提供了LdapNameBuilder,以及LdapUtils中的一些实用方法,这些方法有助于处理LdapName

示例

本节介绍前面章节中涵盖主题的一些示例。第一个示例使用LdapNameBuilder动态构建LdapName

示例5. 使用LdapNameBuilder动态构建LdapName
import org.springframework.ldap.support.LdapNameBuilder;
import javax.naming.Name;

public class PersonRepoImpl implements PersonRepo {
  public static final String BASE_DN = "dc=example,dc=com";

  protected Name buildDn(Person p) {
    return LdapNameBuilder.newInstance(BASE_DN)
      .add("c", p.getCountry())
      .add("ou", p.getCompany())
      .add("cn", p.getFullname())
      .build();
  }
  ...
}

假设一个Person具有以下属性

属性名称 属性值

国家

瑞典

公司

某公司

全名

某人

前面的代码将生成以下判别名

cn=Some Person, ou=Some Company, c=Sweden, dc=example, dc=com

以下示例使用LdapUtils从判别名中提取值

示例6. 使用LdapUtils从判别名中提取值
import org.springframework.ldap.support.LdapNameBuilder;
import javax.naming.Name;
public class PersonRepoImpl implements PersonRepo {
...
  protected Person buildPerson(Name dn, Attributes attrs) {
    Person person = new Person();
    person.setCountry(LdapUtils.getStringValue(dn, "c"));
    person.setCompany(LdapUtils.getStringValue(dn, "ou"));
    person.setFullname(LdapUtils.getStringValue(dn, "cn"));
    // Populate rest of person object using attributes.

    return person;
  }
}

由于Java 1.4及以前版本根本没有提供任何公共判别名实现,Spring LDAP 1.x提供了自己的实现,即DistinguishedName。此实现本身也存在一些缺点,并在2.0版本中已弃用。您现在应该使用LdapName以及前面描述的实用程序。

绑定和解绑

本节介绍如何添加和删除数据。更新将在下一节中介绍。

添加数据

在Java LDAP中插入数据称为绑定。这有点令人困惑,因为在LDAP术语中,“绑定”意味着完全不同的东西。JNDI绑定执行LDAP Add操作,将具有指定判别名的新条目与一组属性关联起来。以下示例使用LdapClient添加数据

示例7. 使用Attributes添加数据
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public void create(Person p) {
      Name dn = buildDn(p);
      ldapClient.bind(dn).attributes(buildAttributes(p)).execute();
   }

   private Attributes buildAttributes(Person p) {
      Attributes attrs = new BasicAttributes();
      BasicAttribute ocattr = new BasicAttribute("objectclass");
      ocattr.add("top");
      ocattr.add("person");
      attrs.put(ocattr);
      attrs.put("cn", "Some Person");
      attrs.put("sn", "Person");
      return attrs;
   }
}

手动构建属性——虽然枯燥且冗长——足以满足许多目的。但是,您可以进一步简化绑定操作,如使用DirContextAdapter简化属性访问和操作中所述。

删除数据

在Java LDAP中删除数据称为解绑。JNDI解绑执行LDAP Delete操作,从LDAP树中删除与指定判别名关联的条目。以下示例使用LdapClient删除数据

示例8. 删除数据
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public void delete(Person p) {
      Name dn = buildDn(p);
      ldapClient.unbind(dn).execute();
   }
}

更新

在Java LDAP中,数据可以通过两种方式修改:使用rebind或使用modifyAttributes

使用Rebind进行更新

rebind是一种粗略的数据修改方式。它基本上是先unbind,然后bind。以下示例调用LDAP的rebind

示例9. 使用rebind进行修改
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public void update(Person p) {
      Name dn = buildDn(p);
      ldapTemplate.bind(dn).attributes(buildAttributes(p)).replaceExisting(true).execute();
   }
}

使用modifyAttributes进行更新

一种更复杂的数据修改方法是使用modifyAttributes。此操作接受一个明确的属性修改数组,并将其在特定条目上执行,如下所示

示例10. 使用modifyAttributes进行修改
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public void updateDescription(Person p) {
      Name dn = buildDn(p);
      Attribute attr = new BasicAttribute("description", p.getDescription())
      ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
      ldapTemplate.modify().name(dn).attributes(item).execute();
   }
}

构建AttributesModificationItem数组需要大量工作。然而,正如我们在使用DirContextAdapter简化属性访问和操作中所述,Spring LDAP为简化这些操作提供了更多帮助。

© . This site is unofficial and not affiliated with VMware.