使用 Spring LDAP 的使用者身分驗證

本節介紹使用 Spring LDAP 進行使用者身分驗證。它包含以下主題

基本身分驗證

雖然 ContextSource 的核心功能是為 LdapClientLdapTemplate 提供 DirContext 實例,但您也可以使用它來針對 LDAP 伺服器驗證使用者身分。 ContextSourcegetContext(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 中包含了一個驗證方法,可提供此功能。

當您使用此方法時,身分驗證會變得非常簡單,如下所示

範例 1. 使用 Spring LDAP 驗證使用者身分
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 上執行任何操作,如下所示

範例 2. 使用 Spring LDAP 對已驗證的 context 執行 LDAP 操作
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);

過時的身分驗證方法

除了前述章節中描述的 authenticate 方法外,您還可以使用許多已棄用的方法進行身分驗證。雖然這些方法運作良好,但我們建議改用 LdapQuery 方法。

使用 Spring Security

雖然前述章節中描述的方法可能足以應付簡單的身分驗證情境,但此領域的需求通常會快速擴展。有許多方面適用,包括身分驗證、授權、網路整合、使用者 context 管理等等。如果您懷疑需求可能會擴展到超出簡單的身分驗證範圍,您絕對應該考慮改用 Spring Security 來達到您的安全性目的。它是一個功能完整、成熟的安全性框架,可解決上述方面以及其他幾個方面。