对于最新的稳定版本,请使用 Spring LDAP 3.3.3! |
基本用法
本节介绍使用 Spring LDAP 的基础知识。它包含以下内容:
搜索和查找使用AttributesMapper
以下示例使用AttributesMapper
以构建包含所有人员对象的所有公用名的列表。
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
对象,如下所示:
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
对象:
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
使用流畅的 API 来构建 LDAP 查询。
假设您要从基本 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 作为输入是推荐使用的方法。 |
这AttributesMapper 只是处理搜索和查找数据时可以使用的可用回调接口之一。看简化属性访问和作DirContextAdapter 对于替代方案。 |
有关LdapQueryBuilder
,请参阅高级 LDAP 查询。
动态构建可分辨名称
可分辨名称的标准 Java 实现 (LdapName
)
在解析可分辨名称时表现良好。然而,在实际使用中,这种实现存在许多缺点:
-
这
LdapName
实现是可变的,这不适合表示身份的对象。 -
尽管它具有可变性质,但用于动态构建或修改可分辨名称的 API 使用
LdapName
很麻烦。 提取索引或(特别)命名组件的值也有点尴尬。 -
许多作
LdapName
抛出检查异常,需要try-catch
错误通常是致命的并且无法以有意义的方式修复的情况的陈述。
为了简化使用可分辨名称,Spring LDAP 提供了一个LdapNameBuilder
,
以及LdapUtils
这在使用LdapName
.
例子
本节介绍了前几节中涵盖的主题的几个示例。
第一个示例动态构建LdapName
通过使用LdapNameBuilder
:
LdapName
通过使用LdapNameBuilder
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
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;
}
}
由于 1.4 之前的 Java 版本根本没有提供任何公共的可分辨名称实现,因此 Spring LDAP 1.x 提供了自己的实现,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;
}
}
手动属性构建虽然枯燥而冗长,但足以满足许多目的。但是,您可以进一步简化绑定作,如简化属性访问和作DirContextAdapter
.
更新
在 Java LDAP 中,可以通过两种方式修改数据:使用rebind
或通过使用modifyAttributes
.
使用重新绑定进行更新
一个rebind
是一种粗略的修改数据的方式。它基本上是一个unbind
后跟一个bind
.
以下示例调用 LDAP 的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
.此作采用显式属性修改数组
并在特定条目上执行它们,如下所示:
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 为简化这些作提供了更多帮助。