使用 Spring LDAP 進行使用者認證
本節介紹使用 Spring LDAP 進行使用者認證。它包含以下主題:
基本認證
雖然 ContextSource
的核心功能是提供供 LdapClient
和 LdapTemplate
使用的 DirContext
例項,但您也可以使用它來針對 LDAP 伺服器進行使用者認證。ContextSource
的 getContext(principal, credentials)
方法正是實現了此功能。它根據 ContextSource
的配置構建一個 DirContext
例項,並使用提供的 principal 和 credentials 進行認證。自定義的 authenticate
方法示例如下:
public boolean authenticate(String userDn, String credentials) {
DirContext ctx = null;
try {
ctx = contextSource.getContext(userDn, credentials);
return true;
} catch (Exception e) {
// Context creation failed - authentication did not succeed
logger.error("Login failed", e);
return false;
} finally {
// It is imperative that the created DirContext instance is always closed
LdapUtils.closeContext(ctx);
}
}
提供給 authenticate
方法的 userDn
必須是要認證使用者的完整 DN(無論 ContextSource
上的 base
設定為何)。通常您需要基於(例如)使用者名稱執行 LDAP 搜尋來獲取此 DN。以下示例展示瞭如何實現:
private String getDnForUser(String uid) {
List<String> result = ldapClient.search()
.query(query().where("uid").is(uid))
.toList((Object ctx) -> ((DirContextOperations) ctx).getNameInNamespace());
if(result.size() != 1) {
throw new RuntimeException("User not found or not unique");
}
return result.get(0);
}
此方法有一些缺點。您被迫需要關心使用者的 DN,只能搜尋使用者的 uid,並且搜尋總是從樹的根(空路徑)開始。更靈活的方法允許您指定搜尋基準、搜尋過濾器和憑據。Spring LDAP 在 LdapClient
中包含了一個提供此功能的認證方法。
當您使用此方法時,認證變得非常簡單,如下所示:
ldapClient.authenticate().query(query().where("uid").is("john.doe")).password("secret").execute();
如在已認證的 Context 上執行操作所述,某些配置可能要求您執行額外的操作才能實際進行認證。有關詳細資訊,請參閱在已認證的 Context 上執行操作。 |
不要編寫自己的自定義 authenticate 方法。請使用 Spring LDAP 中提供的方法。 |
在已認證的 Context 上執行操作
某些認證方案和 LDAP 伺服器要求在建立的 DirContext
例項上執行某些操作才能實際進行認證。您應該測試並確保您的伺服器配置和認證方案的行為方式。否則,可能會導致使用者無論提供的 DN 和憑據是否正確都能進入您的系統。以下示例展示了一個簡單的 authenticate
方法的實現,其中在已認證的 context 上執行了硬編碼的 lookup
操作
public boolean myAuthenticate(String userDn, String credentials) {
DirContext ctx = null;
try {
ctx = contextSource.getContext(userDn, credentials);
// Take care here - if a base was specified on the ContextSource
// that needs to be removed from the user DN for the lookup to succeed.
ctx.lookup(userDn);
return true;
} catch (Exception e) {
// Context creation failed - authentication did not succeed
logger.error("Login failed", e);
return false;
} finally {
// It is imperative that the created DirContext instance is always closed
LdapUtils.closeContext(ctx);
}
}
如果操作可以作為回撥介面的實現提供,而不是將操作限制為始終是 lookup
,那會更好。Spring LDAP 包含了 AuthenticatedLdapEntryContextMapper
回撥介面以及相應的 authenticate
方法。
此方法允許在已認證的 context 上執行任何操作,如下所示:
AuthenticatedLdapEntryContextMapper<DirContextOperations> mapper = new AuthenticatedLdapEntryContextMapper<DirContextOperations>() {
public DirContextOperations mapWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
try {
return (DirContextOperations) ctx.lookup(ldapEntryIdentification.getRelativeName());
}
catch (NamingException e) {
throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeName(), e);
}
}
};
ldapClient.authenticate().query(query().where("uid").is("john.doe")).password("secret").execute(mapper);
使用 Spring Security
雖然前面章節描述的方法對於簡單的認證場景可能已足夠,但這方面的需求通常會快速擴充套件。涉及多個方面,包括認證、授權、Web 整合、使用者上下文管理等。如果您認為需求可能超出簡單的認證範圍,那麼出於安全目的,您絕對應該考慮使用Spring Security。它是一個功能齊全、成熟的安全框架,解決了上述方面以及其他幾個方面的問題。