基本用法
搜索和查找使用AttributesMapper
以下示例使用一个 AttributesMapper 来构建一个包含所有 person 对象的常用名称的列表。
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());
}
}
The inline implementation of AttributesMapper gets the desired attribute value from the Attributes object and returns it. Internally, LdapClient iterates over all entries found, calls the given AttributesMapper for each entry, and collects the results in a list. The list is then returned by the search method.
注意,AttributesMapper 实现可以很容易地修改为返回一个完整的 Person 对象,如下所示:
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 中的“查找”(lookup)。以下示例显示了一个查找 Person 对象的例子:
public class PersonRepoImpl implements PersonRepo {
private LdapClient ldapClient;
...
public Person findPerson(String dn) {
return ldapClient.search().name(dn).toObject(new PersonAttributesMapper());
}
}
上述示例查找指定的DN,并将找到的属性传递给指定的参数——在这种情况下,结果为一个1对象。
构建LDAP查询
LDAP 查询涉及多个参数,包括以下内容:
-
基于LDAP的路径:应在LDAP树的何处开始搜索。
-
搜索范围: 在LDAP树中应搜索多深。
-
要返回的属性。
-
搜索过滤器: 用于在作用域内选择元素的条件。
Spring LDAP 提供了一个 LdapQueryBuilder,用于构建 LDAP 查询,具有流畅的 API。
假设您想要从基础DN dc=261consulting,dc=com 开始进行搜索,将返回属性限制为 cn 和 sn,使用过滤器 (&(objectclass=person)(sn=?)),并希望将 ? 替换为 lastName 参数的值。以下示例展示了如何使用 LdapQueryBuilder 来实现:
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 作为输入参数的方法。 |
The AttributesMapper 仅仅是你在处理搜索和查找数据时可使用的回调接口之一。参见 使用 DirContextAdapter 简化属性访问和操作 以获取其他替代方案。 |
对于 LdapQueryBuilder 的更多信息,请参见 高级 LDAP 查询。
动态构建区分名
The standard Java implementation of Distinguished Name (LdapName)
在解析Distinguished Name方面表现良好。然而,在实际使用中,这种实现存在若干不足之处:
-
The
LdapName实现是可变的,这对于代表身份的对象来说是不合适的。 -
尽管其可变性,使用
LdapName动态构建或修改区分名称(Distinguished Names)的 API 非常繁琐。 从索引(特别是)命名组件提取值也有些笨拙。 -
许多对
LdapName的操作会抛出受检异常,需要在错误通常致命且无法以有意义的方式修复的情况下使用try-catch语句处理。
To simplify working with Distinguished Names, Spring LDAP 提供了一个 LdapNameBuilder,
以及在 LdapUtils 中的若干实用方法,这些方法在处理 LdapName 时特别有用。
示例
本部分展示了前几个部分中所涵盖主题的一些示例。
第一个示例通过使用LdapNameBuilder动态地构建一个LdapName:
LdapNameBuilder 动态构建一个 LdapNameimport 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从区分名称中提取值
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 及更早版本中并未提供任何公开的 Distinguished Name 实现,Spring LDAP 1.x 提供了其 own 的实现,DistinguishedName。
该实现自身存在一些缺点,并在 2.0 版本中已被弃用。现在您应使用 LdapName,并结合前面描述的实用工具。
绑定与解绑
本部分描述了如何添加和删除数据。更新将在下一节中介绍。
添加数据
在Java LDAP中插入数据称为绑定。这有些令人困惑,因为在LDAP术语中,"绑定"意味着完全不同的事情。
通过JNDI绑定执行LDAP添加操作,将具有指定区分名称的新条目与其一组属性关联。
以下示例使用LdapClient添加数据:
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;
}
}
手动构建属性——虽然枯燥且冗长——在许多情况下是足够的。但是,如在
更新
在Java LDAP中,数据可以以两种方式修改:要么使用rebind,要么使用modifyAttributes。
更新使用 Rebind
一个 0 是修改数据的粗暴方式。它基本上是一个 1 后面跟着一个 2。 以下示例调用 LDAP 的 3 :
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。该操作接受一组显式属性修改并对其特定条目执行,如下所示:
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();
}
}
构建 Attributes 和 ModificationItem 数组的工作量很大。然而,正如在 使用 DirContextAdapter 简化属性访问和操作 中所述,
Spring LDAP 为此类操作提供了更多的帮助。