使用 System.DirectoryServices 搜索 Active Directory

使用 System.DirectoryServices 搜索 Active Directory (2006-08-27 16:54:58)
  
看这篇文章中讲的例子,我初步实现了在Active Directory中搜索数据:
代码如下所示:
private void button1_Click(object sender, System.EventArgs e)
    {
      DirectoryEntry rootEntry=new DirectoryEntry(rootPath.Text);
      rootEntry.Username=userID.Text;
      rootEntry.Password=password.Text;
      DirectorySearcher searcher=new DirectorySearcher(rootEntry);
      searcher.PropertiesToLoad.Add("cn");
      searcher.PropertiesToLoad.Add("mail");
      //searcher.PageSize=5;
      searcher.ServerTimeLimit=new TimeSpan(0,0,30);
      searcher.ClientTimeout=new TimeSpan(0,10,0);
      searcher.Filter=searchString.Text;
     
      SearchResultCollection queryResults=searcher.FindAll();
      foreach (SearchResult result in queryResults)
      {
        results.Items.Add(result.Properties["cn"][0]);
       
    }
 
注意要在头上引用:using System.DirectoryServices;
真是太开心了!我参考的帖子的内容如下:
 

使用 System.DirectoryServices 搜索 Active Directory


Duncan Mackenzie
Microsoft Developer Network
2002年11月1日

摘要:Duncan Mackenzie 向您介绍了如何使用 System.DirectoryServices 命名空间来搜索 Microsoft Active Directory 中的信息。

适用于:Microsoft .NET、Microsoft Windows 、Microsoft Active Directory

下载本文的源代码(英文)。(请注意,在示例文件中,程序员的注释使用的是英文,本文中将其译为中文是为了便于读者理解。)

目录

简介

Active Directory 是一种具有特殊用途的数据库,它可以在整个组织范围内复制并轻松扩展,从而更好地存储用户信息、网络配置以及其他在组织范围内进行全局访问所需的数据。它是最强大的操作系统功能之一,如果您的组织拥有 Active Directory,则非常值得在构建自己的应用程序时加以利用。

在本文中,我将详细介绍如何使用 System.DirectoryServices 命名空间来连接 Active Directory、搜索对象并显示搜索结果。当然,System.DirectoryServices 不仅适用于 Active Directory,它还可以用于几种不同的服务,包括普遍使用的 LDAP 协议,但这里主要针对 Active Directory 介绍我的示例。

不过,本文不会详细论述 Active Directory。有关这方面的内容,我向您推荐几篇相关的参考文章:

从 ADSI 转至 System.DirectoryServices

刚开始使用 Active Directory 进行编程的人员可能会对 MSDN 和其他资源上提到的 ADSI 存有疑问。ADSI(即 Active Directory Service Interfaces,Active Directory 服务接口)是一种 COM 库,它使您可以实现非 .NET 语言与 Active Directory 的交互。它是使用 Microsoft Visual Basic 6.0、Visual Basic for Applications (VBA) 和脚本语言访问目录信息的最常用方法。因此,许多关于 Active Directory 的示例和新闻组发言都集中在了 ADSI 上。

令人高兴的是,ADSI 中使用的许多概念都可以经过轻松转换用在 System.DirectoryServices 中,例如 ADSI 示例中显示的 ADSI 路径或属性名。此外,还可以在 COM 和 .NET 库之间使用混合代码。System.DirectoryServices 命名空间中有若干方法和属性可以将 ADSI 对象作为参数接收。当然,即使您从未使用过 ADSI,System.DirectoryServices 也是很容易学习和使用的。

建立连接

System.DirectoryServices 命名空间中有两个主要类,即 DirectoryEntryDirectorySearcher。(还有其他几个类,但这两个是首先需要使用的类。)搜索将使用 DirectorySearcher 类(名称与其功能很般配)来执行。使用该类时,可以不设置任何选项,也可以提供一个根DirectoryEntry 对象。

如果创建了 DirectoryEntry 对象并用作搜索的根,则需要指定路径以说明要连接的服务,还要指定您的安全凭据。创建此单一对象时即建立了指向您的目录的连接。通过提供此DirectoryEntry 对象作为搜索的根,您便可以使用此连接进行查询。或者,如果不指定根对象,DirectorySearcher 将自动绑定到当前域,并使用您的 Microsoft Windows 凭据进行身份验证。

绑定到目录路径

要连接到 Active Directory,您可以使用全局编录 (GC://) 语法来指定路径,也可以使用标准的 LDAP 路径 (LDAP://)。具体使用哪种语法和路径视您的网络环境而定。例如,在我自己的内部网络中,我会使用全局编录语法,因为这使我可以在整个企业网络范围(整个 Active Directory 森林)内进行搜索。我没有使用包含服务器名称的路径,而是仅指定了“GC://dc=home,dc=duncanmackenzie,dc=net”(假设我的域称为 home.duncanmackenzie.net),该路径会告知 ADSI 连接到全局编录服务器的指定域。当然如果您愿意,也可以不指定任何路径来建立连接。如果使用 DirectorySearcher 对象而未提供任何根对象,它将自动使用当前域进行搜索。有关为您的网络确定正确路径的详细信息,请查阅以下参考内容:

验证目录

指定 LDAP 或 GC 路径后,接下来要处理的是安全凭据。您可以使用 DirectoryEntry 类的构造函数来指定用户 ID 和密码,或者在创建该对象的实例后再设置用户 ID 和密码。请不要在您的代码中存储实际的密码/用户 ID,而应当从用户那里检索此信息,或者最好使用集成身份验证。

 
  
Dim rootEntry _ As New DirectoryEntry("GC://dc=home,dc=duncanmackenzie,dc=net", _ userID.Text, _ password.Text)  
 
注意:要使上述代码能够工作,您需要在项目中引用 System.DirectoryServices,并在源文件的顶端添加 Imports System.DirectoryServices (Visual Basic .NET) 或 using System.DirectoryServices; (C#) 代码行。

如果您不指定用户 ID 和密码,System.DirectoryServices 将尝试使用 Windows 集成身份验证进行连接。通常,我倾向于选择集成身份验证,至少在 Microsoft Windows 窗体应用程序中会使用这种验证,因为这样每个用户可以仅使用各自已有的 Active Directory 权限集。使用硬编码的用户 ID 和密码可能会使我的应用程序赋予用户大于所预期的 Active Directory 访问权限,从而带来安全隐患。

执行搜索

创建初始(根)DirectoryEntry 后,您就可以使用 DirectorySearcher 类来执行查询。执行简单的搜索只需要以下几个步骤:

  • 创建 DirectorySearcher 的实例,可以选择使用根 DirectoryEntry 对象。
  • 将搜索筛选器设置为描述搜索条件的字符串。
  • 使用要为每个搜索结果检索的 Active Directory 属性列表填充 PropertiesToLoad 集合。
  • 执行 FindAll 方法并检索结果。

如果需要,您可以跳过几乎所有这些步骤,使用默认设置执行搜索。如果不提供根 DirectoryEntry 对象,DirectorySearcher 将绑定到当前域;如果不提供搜索筛选器,将默认检索所有对象;如果不指定任何 PropertiesToLoad 值,将检索所有属性(您可以读取的属性)。这些默认设置使得 DirectoryServices 类的使用非常简便。不过,我建议您至少使用一个筛选器来限制搜索,并限制加载的属性集,除非您的应用程序确实需要所有属性和所有对象。

 
  
Dim searcher As New DirectorySearcher(rootEntry) searcher.PropertiesToLoad.Add("cn") searcher.PropertiesToLoad.Add("mail") ' searcher.PropertiesToLoad.AddRange(New String() {"cn", "mail"}) ' 将同样有效并节省一些代码 searcher.Filter = "(&(anr=duncan)(objectCategory=person))" Dim results As SearchResultCollection results = searcher.FindAll()  
 

附加选项

还有许多附加搜索选项。这些选项不是必需的,但可以显著影响查询的效果。以下是其中一些附加选项及其简要使用说明:

  • CacheResults 确定搜索结果是否存储在本地客户端计算机上。使用此设置,可以向前或向后浏览搜索结果,否则只能以“向前”模式浏览结果。
  • ClientTimeoutServerTimeLimitServerPageTimeLimit 都是用于防止搜索运行时间过长的超时值。第一个值ClientTimeout 用于控制客户端的等待时间。其他两个时间限制由服务器施加。我建议至少设置 ClientTimeout,以避免您的应用程序出现无限等待的情况。但是,有一点需要注意,即如果到达了某个基于服务器的时间限制,则返回到达该时间点时检索到的条目;如果首先到达了客户端时间限制,则不会返回任何内容。请记住,服务器本身具有可由管理员配置的时间限制,因此在到达您指定的时间限制之前可能会出现超时,从而返回不完整的结果。
  • PageSize 确定一次返回的项数。如果不设置 PageSize 属性或将其设置为 0,则一次返回所有结果。不过,使用分页会使您的应用程序看起来更方便一些。请记住,服务器会确定搜索中返回对象的最大数目,以避免用户造成系统负载过重。所以建议您始终使用分页功能,特别是预计会出现很大的结果集时。在本文末尾的演示中,我将向您说明如何与多线程一起使用分页功能,以生成搜索窗体,并且使用户不必等待。

使用结果

执行搜索后,您将得到一个返回的 SearchResultCollection 类的实例,该实例使您可以对结果进行枚举。这时是否使用了分页并不重要,您仍然是以相同的方式在访问搜索结果。如果下一页的结果尚不可用,您的枚举将被锁定,直至结果就绪。

 
  
Dim result As SearchResult For Each result In results MessageBox.Show(result.Properties("cn")(0)) Next  
 

创建快速搜索演示

经过上述所有步骤,我创建了一个针对 Active Directory 执行搜索的简单应用程序。该示例可以通过本文下载(请单击本文顶部的链接)。如果您希望自己构建,也可以遵照本文进行操作。

为正确配置搜索(包括安全性选项),我必须在所开始的空白 Windows 窗体中设置若干控件,其中包括四个 TextBox 控件(根路径、搜索字符串、用户 ID 和密码)、一个CheckBox 控件(使我可以在集成身份验证和使用用户 ID 及密码之间进行切换)、一个按钮(用于执行搜索)和一个 ListBox 控件(用于显示结果)。我花了一些时间来安排这些控件,并设置了定位属性以使窗体看起来美观一些,使界面可以调整大小,当然这一步完全是可选的。

图 1:使用最终完成的窗体可以执行简单的搜索

现在,我的按钮的单击事件将接收在四个 TextBoxCheckBox 中输入的值,并执行搜索。

 
  
Dim rootEntry _ As New DirectoryEntry(rootPath.Text) If Not integratedAuth.Checked Then rootEntry.Username = userID.Text rootEntry.Password = password.Text End If Dim searcher As New DirectorySearcher(rootEntry) searcher.PropertiesToLoad.Add("cn") searcher.PropertiesToLoad.Add("telephoneNumber") ' searcher.PropertiesToLoad.AddRange(New String() {"cn", "mail"}) ' 将同样有效并节省一些代码 searcher.PageSize = 5 searcher.ServerTimeLimit = New TimeSpan(0, 0, 30) searcher.ClientTimeout = New TimeSpan(0, 10, 0) searcher.Filter = searchString.Text Dim queryResults As SearchResultCollection queryResults = searcher.FindAll()  

得到结果后,将它们逐一添加到 ListBox 中。

 
  
Dim result As SearchResult For Each result In queryResults results.Items.Add(result.Properties("cn")(0)) Next  
 
注意:知道要使用哪些属性以及如何检索这些属性是使用 System.DirectoryServices 时遇到的复杂概念之一。这里有一个很好的 Active Directory 属性名参考资源,至少可供您在处理用户和帐户时使用,即 SDK 参考(英文)。它将属性名映射到 Windows 中用户和组管理单元的信息中。还有一点需要注意,即许多属性可以有多个值,因此属性值可以显示为包含任意多个值的数组。在该示例中,我通过访问属性值数组的第一个元素来检索 cn 属性的值。之所以能够这样做,是因为我碰巧知道 cn 仅包含一个值。当使用多种不同的属性时,您可能需要检查每个属性以确定赋予它的是单个值还是多个值。MSDN 上的 Active Directory Schema 参考为您介绍了这方面内容,它提供了每个属性的详细信息,包括它们的数据类型以及包含的是单个值还是多个值。

完成上述示例后,我们可以从中了解如何针对 Active Directory 执行搜索,但还有两个问题需要解决。第一个问题是,该搜索与我的用户界面(窗体)在同一线程中执行。也就是说,当我的代码等待DirectoryServices 对象的响应时,我的用户界面将无法响应。第二个问题是,我需要手动向 ListBox 中添加检索结果,而许多编程人员更习惯于使用数据绑定将数据集绑定到用户界面。在本文后面的内容中,我将介绍如何使用后台线程提供具有灵活响应的用户界面,以及如何在运行时创建DataTable 以便提供数据绑定功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值