基本用法
使用AttributesMapper進行搜尋和查詢
以下示例使用AttributesMapper來構建所有人員物件的通用名稱列表。
AttributesMapperimport 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,它具有用於構建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作為輸入的方法。 |
AttributesMapper只是在處理搜尋和查詢資料時可以使用的回撥介面之一。有關替代方案,請參閱使用DirContextAdapter簡化屬性訪問和操作。 |
有關LdapQueryBuilder的更多資訊,請參閱高階LDAP查詢。
動態構建判別名
判別名(LdapName)的標準Java實現,在解析判別名方面表現良好。然而,在實際使用中,此實現存在一些缺點
-
LdapName實現是可變的,這對於表示身份的物件來說非常不合適。 -
儘管其可變性,但使用
LdapName動態構建或修改判別名的API很笨拙。提取索引或(特別是)命名元件的值也有些尷尬。 -
LdapName上的許多操作都會丟擲檢查異常,這需要try-catch語句來處理錯誤通常是致命的且無法以有意義的方式修復的情況。
為了簡化判別名的處理,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及以前版本根本沒有提供任何公共判別名實現,Spring LDAP 1.x提供了自己的實現,即DistinguishedName。此實現本身也存在一些缺點,並在2.0版本中已棄用。您現在應該使用LdapName以及前面描述的實用程式。
繫結和解綁
本節介紹如何新增和刪除資料。更新將在下一節中介紹。
新增資料
在Java LDAP中插入資料稱為繫結。這有點令人困惑,因為在LDAP術語中,“繫結”意味著完全不同的東西。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中,資料可以透過兩種方式修改:使用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為簡化這些操作提供了更多幫助。