Angular 7 中的活动目录查找
Active directory lookup in Angular 7
我正在使用 angular 反应形式的输入搜索字段来查找 AD 用户。因此,当您开始输入您的姓名时,您应该会获得该字段的一些自动完成选项。为此,我从我的 angular 应用程序调用网络 api 方法,该方法又 return 给我一个用户列表。我将该用户列表绑定到输入字段数据列表。我在我的网站中使用以下代码 api:-
public List<string> ADUsers()
{
List<string> users = new List<string>();
using (var context = new PrincipalContext(ContextType.Domain, "abc.in"))
{
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
foreach (var result in searcher.FindAll())
{
DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
if(de.Properties["givenName"].Value != null && de.Properties["sn"].Value != null)
users.Add(de.Properties["givenName"].Value + " " + de.Properties["sn"].Value);
}
}
}
return users;
}
由于用户数量太多,return 列表到 angular(20-25 秒)需要时间 return 需要时间反映反应式表单输入字段。我是 angular 的新手,基本上是 .net 开发人员。你能建议一些方法来找出一些响应性的解决方案吗?或者是否可以在 angular 本身中具有该功能,以便我不应该为此调用网络 api 方法?
我在您的代码中发现了几个问题:
- 您没有过滤用户。因此,每次您 运行 时,这段代码都会找到您域中的每个用户。您可以通过使用用户已经输入的文本作为过滤器来更改此设置,并通过限制结果的数量 returned(在自动完成控件中显示 100 多个名称是没有意义的)
PrincipalSearcher
,整个 System.DirectoryServices.AccountManagement
命名空间效率不高。例如,在这种情况下,它会为在幕后找到的每个结果加载每个属性,即使您只使用名字和姓氏也是如此。您可以直接使用 System.DirectoryServices
命名空间(DirectorySearcher
/DirectoryEntry
,这正是 AccountManagement
命名空间在幕后使用的方式)。
这是一个适用于您的情况的示例:
public List<string> ADUsers(string filter) {
if (string.IsNullOrEmpty(filter)) throw new ArgumentNullException(nameof(filter));
List<string> users = new List<string>();
var ds = new DirectorySearcher(
new DirectoryEntry("LDAP://abc.in"), //domain to search
$"(&(objectClass=user)(anr={filter}))", //search filter
new[] { "givenName", "sn" }) //attributes to load
{
SizeLimit = 25 //change this depending on how many you want to show
};
using (var results = ds.FindAll()) {
foreach (SearchResult result in results) {
users.Add($"{result.Properties["givenName"][0]} {result.Properties["sn"][0]}");
}
}
return users;
}
您可以将任何部分名称作为 filter
传递给它,它使用 AD 中称为 Ambiguous Name Resolution 的功能来查找用户。这将在名字、姓氏和其他属性(该文档中的完整列表)中查找部分匹配项。
我也将结果限制为 25,但您可以根据需要进行更改。
此方法还告诉 AD 仅 return 每个结果的 givenName
和 sn
属性,因为这就是我们所关心的.这将减少您的应用和域控制器之间的网络流量。
我也完成了在我的方法中应用过滤器,而且速度非常快。代码如下:-
public List<string> ADUsers(string filter)
{
List<string> users = new List<string>();
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "abc.in");
UserPrincipal user = new UserPrincipal(domainContext)
{
GivenName = filter + "*"
};
PrincipalSearcher pS = new PrincipalSearcher
{
QueryFilter = user
};
PrincipalSearchResult<Principal> results = pS.FindAll();
List<Principal> pc = results.ToList();
foreach (Principal p in pc)
{
DirectoryEntry de = (DirectoryEntry)p.GetUnderlyingObject();
if (de.Properties["givenName"].Value != null && de.Properties["sn"].Value != null)
users.Add(de.Properties["givenName"].Value + " " + de.Properties["sn"].Value);
}
return users;
}
我认为使用 System.DirectoryServices.AccountManagement 不会有任何性能问题,它对我来说效果很好。我仍然将 Gabriel 的答案标记为正确答案(应用过滤器的想法)。
我正在使用 angular 反应形式的输入搜索字段来查找 AD 用户。因此,当您开始输入您的姓名时,您应该会获得该字段的一些自动完成选项。为此,我从我的 angular 应用程序调用网络 api 方法,该方法又 return 给我一个用户列表。我将该用户列表绑定到输入字段数据列表。我在我的网站中使用以下代码 api:-
public List<string> ADUsers()
{
List<string> users = new List<string>();
using (var context = new PrincipalContext(ContextType.Domain, "abc.in"))
{
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
foreach (var result in searcher.FindAll())
{
DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
if(de.Properties["givenName"].Value != null && de.Properties["sn"].Value != null)
users.Add(de.Properties["givenName"].Value + " " + de.Properties["sn"].Value);
}
}
}
return users;
}
由于用户数量太多,return 列表到 angular(20-25 秒)需要时间 return 需要时间反映反应式表单输入字段。我是 angular 的新手,基本上是 .net 开发人员。你能建议一些方法来找出一些响应性的解决方案吗?或者是否可以在 angular 本身中具有该功能,以便我不应该为此调用网络 api 方法?
我在您的代码中发现了几个问题:
- 您没有过滤用户。因此,每次您 运行 时,这段代码都会找到您域中的每个用户。您可以通过使用用户已经输入的文本作为过滤器来更改此设置,并通过限制结果的数量 returned(在自动完成控件中显示 100 多个名称是没有意义的)
PrincipalSearcher
,整个System.DirectoryServices.AccountManagement
命名空间效率不高。例如,在这种情况下,它会为在幕后找到的每个结果加载每个属性,即使您只使用名字和姓氏也是如此。您可以直接使用System.DirectoryServices
命名空间(DirectorySearcher
/DirectoryEntry
,这正是AccountManagement
命名空间在幕后使用的方式)。
这是一个适用于您的情况的示例:
public List<string> ADUsers(string filter) {
if (string.IsNullOrEmpty(filter)) throw new ArgumentNullException(nameof(filter));
List<string> users = new List<string>();
var ds = new DirectorySearcher(
new DirectoryEntry("LDAP://abc.in"), //domain to search
$"(&(objectClass=user)(anr={filter}))", //search filter
new[] { "givenName", "sn" }) //attributes to load
{
SizeLimit = 25 //change this depending on how many you want to show
};
using (var results = ds.FindAll()) {
foreach (SearchResult result in results) {
users.Add($"{result.Properties["givenName"][0]} {result.Properties["sn"][0]}");
}
}
return users;
}
您可以将任何部分名称作为 filter
传递给它,它使用 AD 中称为 Ambiguous Name Resolution 的功能来查找用户。这将在名字、姓氏和其他属性(该文档中的完整列表)中查找部分匹配项。
我也将结果限制为 25,但您可以根据需要进行更改。
此方法还告诉 AD 仅 return 每个结果的 givenName
和 sn
属性,因为这就是我们所关心的.这将减少您的应用和域控制器之间的网络流量。
我也完成了在我的方法中应用过滤器,而且速度非常快。代码如下:-
public List<string> ADUsers(string filter)
{
List<string> users = new List<string>();
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "abc.in");
UserPrincipal user = new UserPrincipal(domainContext)
{
GivenName = filter + "*"
};
PrincipalSearcher pS = new PrincipalSearcher
{
QueryFilter = user
};
PrincipalSearchResult<Principal> results = pS.FindAll();
List<Principal> pc = results.ToList();
foreach (Principal p in pc)
{
DirectoryEntry de = (DirectoryEntry)p.GetUnderlyingObject();
if (de.Properties["givenName"].Value != null && de.Properties["sn"].Value != null)
users.Add(de.Properties["givenName"].Value + " " + de.Properties["sn"].Value);
}
return users;
}
我认为使用 System.DirectoryServices.AccountManagement 不会有任何性能问题,它对我来说效果很好。我仍然将 Gabriel 的答案标记为正确答案(应用过滤器的想法)。