使用 Spring LDAP 進行使用者認證

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

基本認證

雖然 ContextSource 的核心功能是為 LdapClientLdapTemplate 提供 DirContext 例項,但您也可以使用它來針對 LDAP 伺服器認證使用者。ContextSourcegetContext(principal, credentials) 方法正是實現了這一功能。它根據 ContextSource 配置構建一個 DirContext 例項,並使用提供的主體和憑據認證該上下文。一個自定義的認證方法可以像以下示例那樣:

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 中包含一個 authenticate 方法,提供了此功能。

使用此方法時,認證變得像下面這樣簡單:

示例 1. 使用 Spring LDAP 認證使用者
ldapClient.authenticate().query(query().where("uid").is("john.doe")).password("secret").execute();
在已認證的上下文中執行操作中所述,某些設定可能要求您執行額外的操作以實現實際的認證。有關詳細資訊,請參閱在已認證的上下文中執行操作
請勿編寫自己的自定義認證方法。請使用 Spring LDAP 中提供的方法。

在已認證的上下文中執行操作

某些認證方案和 LDAP 伺服器要求在建立的 DirContext 例項上執行一些操作,以使實際的認證發生。您應該測試並確保您的伺服器設定和認證方案如何工作。否則可能導致使用者無論提供的 DN 和憑據如何都被允許進入您的系統。以下示例展示了一個簡單實現的認證方法,其中在已認證的上下文中執行了一個硬編碼的 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 方法。

此方法允許在已認證的上下文中執行任何操作,如下所示:

示例 2. 使用 Spring LDAP 在已認證的上下文中執行 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

雖然前面幾節中描述的方法對於簡單的認證場景可能已足夠,但此領域的需求通常會迅速擴充套件。這涉及到認證、授權、Web 整合、使用者上下文管理等多個方面。如果您懷疑需求可能會超出簡單的認證範圍,那麼您絕對應該考慮使用 Spring Security 來實現您的安全目的。它是一個功能齊全、成熟的安全框架,可以解決上述以及其他幾個方面的問題。

© . This site is unofficial and not affiliated with VMware.