# 对 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 服务器进行身份验证。 ```java // Set up the environment for creating the initial context Hashtable env = new Hashtable(); 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) 显示在创建上下文后如何将上下文的认证信息更改为`“无”`。 ```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) ,它是前一个例子的变体。这次,密码错误会导致身份验证失败。 ```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"); ``` 这会产生以下输出。 ```java 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”`)导致身份验证失败。 ```java // 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"); ``` 这会产生以下输出。 ```java javax.naming.AuthenticationNotSupportedException: custom ... ```