使用 Spring LDAP 的使用者身分驗證
本節介紹使用 Spring LDAP 進行使用者身分驗證。它包含以下主題
基本身分驗證
雖然 ContextSource
的核心功能是為 LdapClient
和 LdapTemplate
提供 DirContext
實例,但您也可以使用它來針對 LDAP 伺服器驗證使用者身分。 ContextSource
的 getContext(principal, credentials)
方法正是如此。它會根據 ContextSource
組態建構 DirContext
實例,並使用提供的 principal 和認證驗證 context。自訂的驗證方法可能如下列範例所示
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 執行操作 以取得詳細資訊。 |
請勿撰寫您自己的自訂驗證方法。請使用 Spring LDAP 中提供的方法。 |
對已驗證的 Context 執行操作
某些身分驗證方案和 LDAP 伺服器需要對建立的 DirContext
實例執行某些操作,才能進行實際的身分驗證。您應該測試並確定您的伺服器設定和身分驗證方案的行為方式。若未執行此操作,可能會導致使用者在未經授權的情況下進入您的系統,無論提供的 DN 和認證為何。以下範例顯示了驗證方法的簡單實作,其中硬式編碼的 lookup
操作是在已驗證的 context 上執行的
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
雖然前述章節中描述的方法可能足以應付簡單的身分驗證情境,但此領域的需求通常會快速擴展。有許多方面適用,包括身分驗證、授權、網路整合、使用者 context 管理等等。如果您懷疑需求可能會擴展到超出簡單的身分驗證範圍,您絕對應該考慮改用 Spring Security 來達到您的安全性目的。它是一個功能完整、成熟的安全性框架,可解決上述方面以及其他幾個方面。