User Authentication using Spring LDAP
本部分涵盖了使用 Spring LDAP 进行用户身份验证的内容。其中包含以下主题:
This section covers user authentication with Spring LDAP. It contains the following topics:
Basic Authentication
虽然 ContextSource
的核心功能是为 LdapClient
和 LdapTemplate
提供 DirContext
实例,但你也可以使用它对 LDAP 服务器的身份验证用户。ContextSource
的 getContext(principal, credentials)
方法的作用与此相同。它根据 ContextSource
配置构建一个 DirContext
实例,并使用指定的 principal 和 credentials 对该上下文进行身份验证。自定义身份验证方法可以像以下示例所示:
While the core functionality of the ContextSource
is to provide DirContext
instances for use by LdapClient
and LdapTemplate
, you can also use it for authenticating users against an LDAP server. The getContext(principal, credentials)
method of ContextSource
does exactly that. It constructs a DirContext
instance according to the ContextSource
configuration and authenticates the context by using the supplied principal and credentials. A custom authenticate method could look like the following example:
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。以下示例展示了如何进行此操作:
The userDn
supplied to the authenticate
method needs to be the full DN of the user to authenticate (regardless of the base
setting on the ContextSource
). You typically need to perform an LDAP search based on (for example) the user name to get this DN. The following example shows how to do so:
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,而且搜索始终从树的根(空路径)开始。更灵活的方法会让你指定搜索基准、搜索过滤器和 credentials。Spring LDAP 在 LdapClient
中包含了一个提供此功能的身份验证方法。
There are some drawbacks to this approach. You are forced to concern yourself with the DN of the user, you can search only for the user’s uid, and the search always starts at the root of the tree (the empty path). A more flexible method would let you specify the search base, the search filter, and the credentials. Spring LDAP includes an authenticate method in LdapClient
that provides this functionality.
当你使用此方法时,身份验证将变得像以下一样简单:
When you use this method, authentication becomes as simple as follows:
ldapClient.authenticate().query(query().where("uid").is("john.doe")).password("secret").execute();
如 Performing Operations on the Authenticated Context 中所述,在某些设置中,可能需要执行额外操作才能进行实际身份验证。有关详细信息,请参阅 Performing Operations on the Authenticated Context。 |
As described in the Performing Operations on the Authenticated Context, some setups may require you to perform additional operations to get actual authentication to occur. See Performing Operations on the Authenticated Context for details. |
不要编写您自己的自定义 authenticate 方法。使用 Spring LDAP 中提供的那些方法。 |
Do not write your own custom authenticate methods. Use the ones provided in Spring LDAP. |
Performing Operations on the Authenticated Context
某些身份验证方案和 LDAP 服务器要求在创建的 DirContext
实例上执行某些操作才能进行实际身份验证。你应该测试并确保服务器设置和身份验证方案的行为方式。如果不这么做,可能会导致用户无论指定的 DN 和 credentials 如何而被接纳到你的系统中。以下示例展示了一个幼稚的身份验证方法实现,其中对经过身份验证的上下文执行硬编码的 lookup
操作:
Some authentication schemes and LDAP servers require some operation to be performed on the created DirContext
instance for the actual authentication to occur. You should test and make sure how your server setup and authentication schemes behave. Failure to do so might result in users being admitted into your system regardless of the supplied DN and credentials. The following example shows a naïve implementation of an authenticate method where a hard-coded lookup
operation is performed on the authenticated 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
方法。
It would be better if the operation could be provided as an implementation of a callback interface, rather than limiting the operation to always be a lookup
. Spring LDAP includes the AuthenticatedLdapEntryContextMapper
callback interface and a corresponding authenticate
method.
此方法允许对经过身份验证的上下文执行任何操作,如下所示:
This method lets any operation be performed on the authenticated context, as follows:
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);
Obsolete Authentication Methods
除了前面部分中描述的 authenticate
方法之外,你还可以使用许多弃用的身份验证方法。虽然这些方法工作正常,但我们建议改用 LdapQuery
方法。
In addition to the authenticate
methods described in the preceding sections, you can use a number of deprecated methods for authentication. While these work fine, we recommend using the LdapQuery
methods instead.
Using Spring Security
尽管上一部分中描述的方法可能足以用于简单的身份验证场景,但此领域的要求通常会迅速增加。应用的方面很多,包括身份验证、授权、Web 集成、用户上下文管理等。如果您怀疑要求可能扩展到不只是简单身份验证,那么您肯定应该考虑将 @"33" 用于您的安全目的。它是一个成熟的全功能安全框架,它可以解决上述方面以及其他一些方面。
While the approach described in the preceding sections may be sufficient for simple authentication scenarios, requirements in this area commonly expand rapidly. A multitude of aspects apply, including authentication, authorization, web integration, user context management, and others. If you suspect that the requirements might expand beyond just simple authentication, you should definitely consider using Spring Security for your security purposes instead. It is a full-featured, mature security framework that addresses the aforementioned aspects as well as several others.