基本用法
本節說明 Spring LDAP 的基本用法。內容包含下列項目
使用 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());
}
}
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 搜尋的 overloaded 方法。這是為了適應盡可能多的不同使用案例和程式設計風格偏好。對於絕大多數使用案例,建議使用將 LdapQuery 作為輸入的方法。 |
AttributesMapper 只是您可以在處理搜尋和查詢資料時使用的可用回呼介面之一。如需替代方案,請參閱 使用 DirContextAdapter 簡化屬性存取與操作。 |
如需 LdapQueryBuilder
的詳細資訊,請參閱 進階 LDAP 查詢。
動態建立識別名稱
Distinguished Name (LdapName
) 的標準 Java 實作在解析識別名稱方面表現良好。但是,在實際使用中,此實作有許多缺點
-
LdapName
實作是可變的,這與代表身分識別的物件非常不符。 -
儘管
LdapName
具有可變性,但使用LdapName
動態建立或修改識別名稱的 API 相當繁瑣。提取索引或(特別是)具名元件的值也有點笨拙。 -
LdapName
上的許多操作都會擲回 checked exceptions,對於錯誤通常是致命且無法以有意義的方式修復的情況,需要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;
}
}
由於 1.4 及更早版本的 Java 版本根本沒有提供任何公用識別名稱實作,因此 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 提供了更多協助來簡化這些操作。