# 经常问的问题

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

本课程回答用户在使用 JNDI 访问 LDAP 服务时经常遇到的常见问题。在命名和目录操作课程的[故障排除提示](../ops/faq.html)中回答了一些常见问题。

* * *

1.  ## 上下文：

2.  [多线程访问的上下文安全吗？](#1)
3.  [为什么 LDAP 提供程序会忽略我的安全环境属性？](#2)
4.  [为什么我一直收到 CommunicationException？](#3)
5.  [如何获取 LDAP 消息的痕迹？](#4)
6.  [如何使用其他身份验证机制，如 Kerberos？](#5)
7.  [我应该在更改密码时启用 ssl 吗？](#6)

    ## 属性：

8.  [当我要求一个属性时，我会回到另一个属性。为什么？](#7)
9.  [我如何知道属性值的类型？](#8)
10.  [如何以字符串或字节数组以外的形式返回属性值？](#9)
11.  [为什么在搜索中将“*”作为属性值不能正常工作？](#10)

    ## 搜索：

12.  [为什么搜索过滤器中的通配符始终不起作用？](#11)
13.  [当我知道目录中有更多条目时，为什么我只返回 _n_ 条目数？](#12)
14.  [如何通过搜索传递控件？](#13)
15.  [我如何知道我收到了多少搜索结果？](#14)

    ## 名称：

16.  [为什么我的 SearchResult 中有一个空字符串作为名称？](#15)
17.  [为什么我在 SearchResult 中将 URL 字符串作为名称？](#16)
18.  [传递给上下文方法的 Name 参数是什么类型的？](#17)
19.  [我可以将从 NameParser 返回的名称传递给 Context 方法吗？](#18)
20.  [我用于 `Context.SECURITY_PRINCIPAL` 属性的名称和目录之间的关系是什么？](#19)
21.  [为什么我从目录中读取的名称中出现了奇怪的引号和转义？](#20)
22.  [如何获取 LDAP 条目的完整 DN？](#21)

* * *

答案取决于实现。这是因为 [`Context`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html)和 [`DirContext`](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/DirContext.html)接口没有指定同步要求。 JDK 中的 LDAP 实现针对单线程访问进行了优化。如果你有多个线程访问相同的 `Context` 实例，那么每个线程在使用它时需要锁定 `Context` 实例。这也适用于从同一 `Context` 实例派生的任何 `NamingEnumeration` 。但是，多个线程可以在没有锁的情况下同时访问 _ 不同的 _ `Context` 实例（甚至是那些从相同的初始上下文派生的实例）。

 [`Context.SECURITY_CREDENTIALS` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#SECURITY_CREDENTIALS)（`“java.naming.security，为什么 LDAP 提供程序会忽略我的安全环境属性。凭证“`）属性还是将其设置为空字符串？

如果你提供一个空字符串，空`字节` / `char` 数组，或 `null` 到 `Context.SECURITY_CREDENTIALS` 环境属性，那么即使 `Context.SECURITY_AUTHENTICATION` 属性设置为`“simple”`，也会发生匿名绑定。这是因为对于简单身份验证，LDAP 要求密码非空。如果未提供密码，则协议会自动将身份验证转换为`“无”`。

 [`CommunicationException` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/CommunicationException.html)？

您可能正在与仅支持 LDAP v2 的服务器通信。有关如何设置版本号的示例，请参阅 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/ldap/misc/version.html)的其他课程。

尝试使用`“com.sun.jndi.ldap.trace.ber”`环境属性。如果此属性的值是 `java.io.OutputStream` 的实例，则 LDAP 提供程序发送和接收的 BER 缓冲区的跟踪信息将写入该流。如果属性的值为 `null` ，则不写入跟踪输出。

例如，以下代码将跟踪输出发送到 `System.err` 。

```
env.put("com.sun.jndi.ldap.trace.ber", System.err);

```

有关如何使用 Kerberos 身份验证的信息，请按照 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/ldap/security/gssapi.html)的 GSS-API / Kerberos v5 身份验证中的说明进行操作。要使用其他身份验证机制，请参阅 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/ldap/security/mechanism.html)的“使用任意 SASL 机制”部分。

 /

这实际上取决于您使用的目录服务器。如果未启用 SSL 但某些目录服务器允许更改密码，则某些目录服务器将不允许您更改密码。启用 S​​SL 以在通信通道中保护您的密码是件好事。

您正在使用的属性名称可能是另一个属性的同义词。在这种情况下，LDAP 服务器可能会返回规范属性名称而不是您提供的名称。当您查看服务器返回的`属性`时，您需要使用规范名称而不是同义词。

例如，`“fax”`可能是规范属性名称`“facsimiletelephonenumber”`的同义词。如果您要求`“传真”`，服务器将返回名为`“facsimiletelephonenumber”`的属性。有关同义词和有关属性名称的其他问题的详细信息，请参阅[命名和目录操作](../ops/attrnames.html)课程。

属性的值可以是 `java.lang.String` 或 `byte []` 。有关哪些属性值作为 `byte []` 返回的信息，请参见 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/ldap/misc/attrs.html)的其他部分。要以编程方式执行此操作，可以使用 `instanceof` 运算符来检查从 LDAP 提供程序返回的属性值。

目前你不能。 LDAP 提供程序仅返回 `java.lang.String` 或 `byte []` 的属性值。请参阅 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/ldap/misc/attrs.html)的其他部分。

当您使用以下形式的 `search（）`时，属性值被视为文字;也就是说，目录条目中的属性应该包含该值： [`搜索（名称，属性 matchingAttrs）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/DirContext.html#search-javax.naming.Name-javax.naming.directory.Attributes-) 要使用通配符，您应该使用[的字符串过滤形式] HTG6] search（），如下。 [`搜索（名称，字符串过滤器，SearchControls ctls）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/DirContext.html#search-javax.naming.Name-java.lang.String-javax.naming.directory.SearchControls-)
[`搜索（名称名称，String filterExpr，Object [] filterArgs，SearchControls ctls）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/DirContext.html#search-javax.naming.Name-java.lang.String-java.lang.Object:A-javax.naming.directory.SearchControls-)

对于最后一种形式，通配符必须出现在 `filterExpr` 参数中，而不是出现在 `filterArgs` 中。 `filterArgs` 中的值也被视为文字。

出现在属性值之前或之后的通配符（例如`“attr = * I *”`）表示服务器将使用属性的子字符串匹配规则搜索匹配的属性值。如果属性的定义没有子字符串匹配规则，则服务器无法找到该属性。您必须使用相等或“现在”过滤器进行搜索。

 某些服务器配置为限制可以返回的条目数。其他人也限制了搜索期间可以检查的条目数。检查您的服务器配置。

本教程不解释控件。查看 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/ldap/ext/context.html)。

在列举结果时，您必须保持计数。 LDAP 不提供此信息。

 [`SearchResult` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/SearchResult.html)中有一个空字符串作为名称？

[`getName（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/NameClassPair.html#getName--) 总是将 _ 相对 _ 的名称返回到搜索的 _ 目标上下文 _。因此，如果目标上下文满足搜索过滤器，则返回的名称将为“”（空名称），因为这是相对于目标上下文的名称。有关详细信息，请参阅[搜索结果](result.html)部分。

 [`SearchResult` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/SearchResult.html)中有一个 URL 字符串作为名称？

通过跟随别名或引用来检索 LDAP 条目，因此其名称是 URL。有关详细信息，请参阅[搜索结果](result.html)课程。

 [`名称`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Name.html) 参数传递给 [`上下文`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html) 和 [`DirContext`](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/DirContext.html)方法？ - [`化合物名`](https://docs.oracle.com/javase/8/docs/api/javax/naming/CompoundName.html) 或 [`复合名称`](https://docs.oracle.com/javase/8/docs/api/javax/naming/CompositeName.html) ？

字符串表单接受复合名称的字符串表示形式。也就是说，使用字符串名称相当于调用 `new CompositeName（stringName）`并将结果传递给 `Context` / `DirContext` 方法。 `Name` 参数可以是实现 `Name` 接口的任何对象。如果它是 `CompositeName` 的实例，则将该名称视为复合名称;否则，它被视为复合名称。

 [`NameParser` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/NameParser.html)的名称传递给 [`上下文`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html) 方法吗？

这与前一个问题有关。是的你可以。 [`NameParser.parse（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/NameParser.html#parse-java.lang.String-) 返回实现 `Name` 接口的复合名称。此名称可以传递给 `Context` 方法，该方法将其解释为复合名称。

 [`Context.SECURITY_PRINCIPAL` ](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#SECURITY_PRINCIPAL)属性和目录的名称之间的关系是什么？

您可以将主体名称视为来自与目录不同的命名空间。有关 LDAP 身份验证机制的详细信息，请参阅 [RFC 2829](http://www.ietf.org/rfc/rfc2829.txt) 和[安全](../ldap/security.html)部分。 JDK 中的 LDAP 服务提供程序接受字符串主体名称，它直接传递给 LDAP 服务器。一些 LDAP 服务器接受 DN，而其他服务器支持 [RFC 2829](http://www.ietf.org/rfc/rfc2829.txt) 提出的方案。

JDK 中的 LDAP 名称解析器在引用规则方面是保守的，但它仍然生成“正确”的名称。另外，请记住 [`NamingEnumeration`](https://docs.oracle.com/javase/8/docs/api/javax/naming/NamingEnumeration.html)返回的条目名称是可以传递回 `Context` 和 `DirContext` 方法的复合名称。因此，如果名称包含与复合名称语法冲突的字符（例如正斜杠字符“/”），则 LDAP 提供程序将提供编码以确保将斜杠字符视为 LDAP 名称的一部分而不是作为复合名称分隔符。

开始使用 [`LdapName`](https://docs.oracle.com/javase/8/docs/api/javax/naming/ldap/LdapName.html)和 [`Rdn`](https://docs.oracle.com/javase/8/docs/api/javax/naming/ldap/Rdn.html)类，可以轻松进行名称操作。

您可以使用 [`NameClassPair.getNameInNamespace（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/NameClassPair.html#getNameInNamespace--) 。

* * *