# 对 LDAP 进行身份验证的模式

> 原文： [https://docs.oracle.com/javase/tutorial/jndi/ldap/authentication.html](https://docs.oracle.com/javase/tutorial/jndi/ldap/authentication.html)

在 LDAP 中，身份验证信息在“绑定”操作中提供。在 LDAP v2 中，客户端通过向服务器发送包含身份验证信息的“绑定”操作来启动与 LDAP 服务器的连接。

在 LDAP v3 中，此操作用于相同的目的，但它是可选的。发送 LDAP 请求而不执行“绑定”的客户端被视为 _ 匿名 _ 客户端（有关详细信息，请参阅[匿名](anonymous.html)部分）。在 LDAP v3 中，“绑定”操作可以在连接期间的任何时间发送，可能不止一次。客户端可以在连接中间发送“绑定”请求以更改其标识。如果请求成功，则丢弃在连接上使用旧标识的所有未完成请求，并且连接与新标识关联。

“绑定”操作中提供的认证信息取决于客户端选择的 _ 认证机制 _。有关身份验证机制的讨论，请参阅[身份验证机制](auth_mechs.html)。

## 使用 JNDI 对 LDAP 进行身份验证

在 JNDI 中，身份验证信息在环境属性中指定。当您使用 [`InitialDirContext`](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/InitialDirContext.html)类（或其超类或子类）创建初始上下文时，您提供了一组环境属性，其中一些可能包含身份验证信息。您可以使用以下环境属性来指定身份验证信息。

*   [`Context.SECURITY_AUTHENTICATION` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#SECURITY_AUTHENTICATION)（`“java.naming.security.authentication”`）。
    指定要使用的身份验证机制。对于 JDK 中的 LDAP 服务提供者，这可以是以下字符串之一：`“无”`，`“简单”`， _sasl_mech_ ，其中 _sasl_mech_ 是一个以空格分隔的 SASL 机制名称列表。有关这些字符串的说明，请参见[验证机制](auth_mechs.html)。
*   [`Context.SECURITY_PRINCIPAL` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#SECURITY_PRINCIPAL)（`“java.naming.security.principal”`）。
    指定进行身份验证的用户/程序的名称，并取决于 `Context.SECURITY_AUTHENTICATION` 属性的值。有关详细信息和示例，请参阅本课程的下几节。
*   [`Context.SECURITY_CREDENTIALS` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#SECURITY_CREDENTIALS)（`“java.naming.security.credentials”`）。
    指定进行身份验证的用户/程序的凭据，并取决于 `Context.SECURITY_AUTHENTICATION` 属性的值。有关详细信息和示例，请参阅本课程的下几节。

创建初始上下文时，基础 LDAP 服务提供程序从这些环境属性中提取身份验证信息，并使用 LDAP“绑定”操作将它们传递给服务器。

[`following example`](examples/Simple.java) 通过使用简单的明文密码显示客户端如何向 LDAP 服务器进行身份验证。

```
// Set up the environment for creating the initial context
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");

// Authenticate as S. User and password "mysecret"
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, 
        "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "mysecret");

// Create the initial context
DirContext ctx = new InitialDirContext(env);

// ... do something useful with ctx

```

## 为上下文使用不同的身份验证信息

如果要对现有上下文使用不同的身份验证信息，则可以使用 [`Context.addToEnvironment（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#addToEnvironment-java.lang.String-java.lang.Object-) 和 [`Context.removeFromEnvironment（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#removeFromEnvironment-java.lang.String-) 更新包含身份验证信息的环境属性。对上下文的方法的后续调用将使用新的认证信息与服务器通信。

[`following example`](examples/UseDiff.java) 显示在创建上下文后如何将上下文的认证信息更改为`“无”`。

```
// Authenticate as S. User and the password "mysecret"
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, 
        "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "mysecret");

// Create the initial context
DirContext ctx = new InitialDirContext(env);

// ... do something useful with ctx

// Change to using no authentication
ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "none");

// ... do something useful with ctx

```

## 身份验证失败

身份验证可能由于多种原因而失败。例如，如果您提供不正确的身份验证信息，例如密码或主体名称不正确，则会抛出 [`AuthenticationException`](https://docs.oracle.com/javase/8/docs/api/javax/naming/AuthenticationException.html)。

这是 [`an example`](examples/BadPasswd.java) ，它是前一个例子的变体。这次，密码错误会导致身份验证失败。

```
// Authenticate as S. User and give an incorrect password
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, 
        "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "notmysecret");

```

这会产生以下输出。

```
javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]
        ...

```

由于不同的服务器支持不同的身份验证机制，因此您可能会请求服务器不支持的身份验证机制。在这种情况下，将抛出 [`AuthenticationNotSupportedException`](https://docs.oracle.com/javase/8/docs/api/javax/naming/AuthenticationNotSupportedException.html)。

这是 [`an example`](examples/BadAuth.java) ，它是前一个例子的变体。这次，不支持的身份验证机制（`“custom”`）导致身份验证失败。

```
// Authenticate as S. User and the password "mysecret"
env.put(Context.SECURITY_AUTHENTICATION, "custom");
env.put(Context.SECURITY_PRINCIPAL, 
        "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "mysecret");

```

这会产生以下输出。

```
javax.naming.AuthenticationNotSupportedException: custom
        ...

```