无法在 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);
这在本地机器和服务器上都可以正常工作。
【讨论】:
PrincipalContext
和 PrincipalSearcher
在后台使用 DirectoryEntry
和 DirectorySearcher
。我怀疑区别在于您的 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 数据的主要内容,如果未能解决你的问题,请参考以下文章
我无法从 Windows 托管的 Web API 上的 IIS 访问 wkhtmltopdf
如何为托管在 Azure 上的 Web 应用程序和托管在窗口的 IIS 服务器上的 Web 应用程序使用相同的自定义域?