无法在 IIS 托管应用程序上使用 System.DirectoryServices.AccountManagement 获取 LDAP 数据

Posted

技术标签:

【中文标题】无法在 IIS 托管应用程序上使用 System.DirectoryServices.AccountManagement 获取 LDAP 数据【英文标题】:Cannot get LDAP data using System.DirectoryServices.AccountManagement on IIS hosted app 【发布时间】:2022-01-08 19:06:47 【问题描述】:

我正在使用 System.DirectoryServices.AccountManagement 包从 LDAP 获取用户数据,它在我的本地机器上运行良好,但在服务器上,它给出了错误提示:

**发生操作错误。

at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   at System.DirectoryServices.DirectoryEntry.Bind()
   at System.DirectoryServices.DirectoryEntry.get_AdsObject()
   at System.DirectoryServices.PropertyValueCollection.PopulateList()
   at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
   at System.DirectoryServices.PropertyCollection.get_Item(String propertyName)
   at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInitNoContainer()
   at System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit()
   at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize()
   at System.DirectoryServices.AccountManagement.PrincipalContext.get_QueryCtx()
   at System.DirectoryServices.AccountManagement.PrincipalSearcher.SetDefaultPageSizeForContext()
   at System.DirectoryServices.AccountManagement.PrincipalSearcher..ctor(Principal queryFilter)  

**

.NET Core 版本是 3.1,System.DirectoryServices.AccountManagement 版本是 6.0,应用托管在 VM 上的 IIS 上(IIS 版本 8.0)。我使用的代码是:

List < ApplicationUser > users = new List < ApplicationUser > ();

using(var ctx = new PrincipalContext(ContextType.Domain, "mydomain")) 

  var userPrinciple = new UserPrincipal(ctx);
  using(var search = new PrincipalSearcher(userPrinciple)) 
    var results = search.FindAll().OrderBy(u => u.DisplayName);
    foreach(UserPrincipal domainUser in results) 
      var adUser = new ApplicationUser 
          Email = domainUser.EmailAddress,
          FirstName = domainUser.Name,
          PhoneNumber = domainUser.VoiceTelephoneNumber,
          UserName = domainUser.UserPrincipalName,
          EmployeeId = domainUser.EmployeeId
      ;

      if (!String.IsNullOrWhiteSpace(adUser.Email)) 
        users.Add(adUser);
      

    
  

到目前为止,我已尝试将应用程序池身份更改为网络服务,但没有成功。

【问题讨论】:

this answer可以帮到你吗? 【参考方案1】:

堆栈跟踪显示异常发生在DirectoryEntry.Bind,这是它最初连接到 AD 的时间。因此,您的计算机和服务器之间肯定有所不同。

服务器是否可以访问该域?是否有防火墙阻止访问?

您的计算机是否已加入域,但服务器未加入?如果是这种情况,请尝试在 PrincipalContext 构造函数中使用域的完整 DNS 名称,如果您还没有使用(例如 mydomain.com 而不仅仅是 mydomain)。

您是否在服务器上使用模拟?如果是这样,那可能就是问题所在。见这里:https://***.com/a/21547199/1202807

这是解决 ASP.NET(不是 Core)的问题,但可能是类似的问题。

【讨论】:

我想知道我的计算机和服务器可能有一些连接差异或类似的东西,但问题是别的东西。无论如何,我使用了备用代码并且它现在可以工作了。感谢您的宝贵回答。【参考方案2】:

搜索了很多,我找到了一个交替的解决方案:

List<ApplicationUser> users = new List<ApplicationUser>();
       
        using (var root = new DirectoryEntry(_ladapSettings.LDAPPathString, _ladapSettings.UserName, _ladapSettings.Password))
        
            using (var searcher = new DirectorySearcher(root))
            
                searcher.Filter = $"(&(objectCategory=person)(objectClass=user)(|(displayName=*filter)(displayName=filter*)))";
                var query = searcher.FindAll();

                foreach (SearchResult results in query)
                
                    var de = results.GetDirectoryEntry();

                    if(de != null)
                    

                        var adUser = new ApplicationUser
                        
                            Email = de.Properties["mail"].Value?.ToString(),
                            UserName = de.Properties["mail"].Value?.ToString(),
                            FirstName = de.Properties["givenname"].Value?.ToString(),
                            LastName = de.Properties["sn"].Value?.ToString(),
                            PhoneNumber = de.Properties["telephoneNumber"].Value?.ToString(),
                            EmployeeId = de.Properties["employeeid"].Value?.ToString()
                        ;

                        if (!String.IsNullOrWhiteSpace(adUser.Email))
                        
                            users.Add(adUser);
                        

                    
                
            

这在本地机器和服务器上都可以正常工作。

【讨论】:

PrincipalContextPrincipalSearcher 在后台使用 DirectoryEntryDirectorySearcher。我怀疑区别在于您的 LDAP 字符串。使用new PrincipalContext(ContextType.Domain, "mydomain") 将转换为LDAP://mydomain 的LDAP 字符串。因此,如果您的服务器不理解您的域的简称,它就无法工作。在您的新代码中,如果您使用的是使用域的 DNS 名称 (LDAP://mydomain.com) 的 LDAP 字符串,那么这会有所不同。 我确实认为最好还是直接使用DirectorySearcher。但是您可以通过不使用results.GetDirectoryEntry() 使您的代码运行得更快。我在一篇关于在针对 AD 编程时获得更好性能的文章中解释了为什么:Active Directory: Better Performance

以上是关于无法在 IIS 托管应用程序上使用 System.DirectoryServices.AccountManagement 获取 LDAP 数据的主要内容,如果未能解决你的问题,请参考以下文章

iis托管管道模式-学习

无法在 IIS 中托管 Web 服务

我无法从 Windows 托管的 Web API 上的 IIS 访问 wkhtmltopdf

如何为托管在 Azure 上的 Web 应用程序和托管在窗口的 IIS 服务器上的 Web 应用程序使用相同的自定义域?

当我的应用程序托管在 IIS 上时,Microsoft Exchange Web 服务 (EWS) 无法正常工作

WCF服务的IIS托管(网站托管)