基本用法
本節介紹 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 中稱為“查詢”(lookup)。以下示例顯示了對 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 提供了一個帶有流暢 API 的 LdapQueryBuilder
,用於構建 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 查詢。
動態構建識別名
識別名 (LdapName
) 的標準 Java 實現在解析識別名方面表現良好。然而,在實際使用中,此實現存在一些缺點
-
LdapName
實現是可變的,這對於表示身份的物件來說不太合適。 -
儘管其可變性,但使用
LdapName
動態構建或修改識別名的 API 很繁瑣。提取索引或(特別是)命名元件的值也有點麻煩。 -
LdapName
上的許多操作會丟擲受檢異常,這在錯誤通常是致命且無法有效修復的情況下需要try-catch
語句。
為了簡化識別名的使用,Spring LDAP 提供了 LdapNameBuilder
,以及 LdapUtils
中的一些實用方法,有助於處理 LdapName
。
示例
本節介紹前面各節主題的一些示例。第一個示例使用 LdapNameBuilder
動態構建 LdapName
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
具有以下屬性
屬性名稱 | 屬性值 |
---|---|
|
Sweden |
|
Some Company |
|
Some 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 及之前的版本根本沒有提供任何公共的識別名實現,Spring LDAP 1.x 提供了自己的實現 DistinguishedName
。此實現自身存在一些缺點,並在 2.0 版本中已棄用。現在應使用 LdapName
以及前面描述的工具類。
繫結和解綁
本節介紹如何新增和刪除資料。更新將在下一節中介紹。
新增資料
在 Java LDAP 中插入資料稱為繫結 (binding)。這有點令人困惑,因為在 LDAP 術語中,“bind”的意思完全不同。JNDI 繫結執行 LDAP 新增 (Add) 操作,將具有指定識別名的新條目與一組屬性關聯起來。以下示例使用 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 中刪除資料稱為解綁 (unbinding)。JNDI 解綁執行 LDAP 刪除 (Delete) 操作,從 LDAP 樹中移除與指定識別名關聯的條目。以下示例使用 LdapClient
刪除資料
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
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 提供了更多幫助來簡化這些操作。