无法在 IIS 托管应用程序上使用 System.DirectoryServices.AccountManagement 获取 LDAP 数据
Cannot get LDAP data using System.DirectoryServices.AccountManagement on IIS hosted app
我正在使用 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);
}
}
}
}
到目前为止,我已尝试将应用程序池标识更改为网络服务,但没有成功。
堆栈跟踪显示异常发生在 DirectoryEntry.Bind
,也就是它最初连接到 AD 时。所以你的电脑和服务器之间一定有什么不同。
服务器是否可以访问域?是否有防火墙阻止访问?
您的计算机是否加入了域,但服务器没有?如果是这种情况,请尝试在 PrincipalContext
构造函数中使用域的完整 DNS 名称,如果您还没有这样做的话(例如 mydomain.com
而不仅仅是 mydomain
)。
您是否在服务器上使用模拟?如果是这样,那可能就是问题所在。看这里:
那是在解决 ASP.NET(不是核心)问题,但这可能是一个类似的问题。
经过大量搜索,我找到了一个替代解决方案:
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);
}
}
}
}
这在本地机器和服务器上都能正常工作。
我正在使用 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);
}
}
}
}
到目前为止,我已尝试将应用程序池标识更改为网络服务,但没有成功。
堆栈跟踪显示异常发生在 DirectoryEntry.Bind
,也就是它最初连接到 AD 时。所以你的电脑和服务器之间一定有什么不同。
服务器是否可以访问域?是否有防火墙阻止访问?
您的计算机是否加入了域,但服务器没有?如果是这种情况,请尝试在 PrincipalContext
构造函数中使用域的完整 DNS 名称,如果您还没有这样做的话(例如 mydomain.com
而不仅仅是 mydomain
)。
您是否在服务器上使用模拟?如果是这样,那可能就是问题所在。看这里:
那是在解决 ASP.NET(不是核心)问题,但这可能是一个类似的问题。
经过大量搜索,我找到了一个替代解决方案:
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);
}
}
}
}
这在本地机器和服务器上都能正常工作。