如何获取Active Directory中的用户组? (c#,asp.net)

我使用此代码来获取当前用户的组。 但我想手动给用户,然后得到他的团体。 我该怎么做?

using System.Security.Principal; public ArrayList Groups() { ArrayList groups = new ArrayList(); foreach (IdentityReference group in System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups) { groups.Add(group.Translate(typeof(NTAccount)).ToString()); } return groups; } 

如果您使用.NET 3.5或更高版本,则可以使用新的System.DirectoryServices.AccountManagement (S.DS.AM)命名空间,这比以前更容易。

在这里阅读所有信息: 在.NET Framework 3.5中pipe理目录安全主体

更新:不幸的是,旧的MSDN杂志文章不再在线了 – 您需要从Microsoft 下载2008年1月MSDN杂志的CHM,并阅读其中的文章。

基本上,你需要有一个“主要的背景”(通常是你的域),一个用户的主体,然后你很容易得到它的组:

 public List<GroupPrincipal> GetGroups(string userName) { List<GroupPrincipal> result = new List<GroupPrincipal>(); // establish domain context PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain); // find your user UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName); // if found - grab its groups if(user != null) { PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups(); // iterate over all groups foreach(Principal p in groups) { // make sure to add only group principals if(p is GroupPrincipal) { result.Add((GroupPrincipal)p); } } } return result; } 

这就是全部! 你现在有一个用户所属的授权组的结果(列表) – 遍历它们,打印出他们的名字或者你需要做的任何事情。

更新:为了访问UserPrincipal对象上不存在的某些属性,需要深入底层的DirectoryEntry

 public string GetDepartment(Principal principal) { string result = string.Empty; DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry); if (de != null) { if (de.Properties.Contains("department")) { result = de.Properties["department"][0].ToString(); } } return result; } 

更新#2:似乎不应该太难,把这两个代码片段在一起….但确定 – 这里是:

 public string GetDepartment(string username) { string result = string.Empty; // if you do repeated domain access, you might want to do this *once* outside this method, // and pass it in as a second parameter! PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain); // find the user UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username); // if user is found if(user != null) { // get DirectoryEntry underlying it DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry); if (de != null) { if (de.Properties.Contains("department")) { result = de.Properties["department"][0].ToString(); } } } return result; } 

GetAuthorizationGroups()找不到嵌套的组。 要真正获得给定用户的所有组是(包括嵌套组)的成员,请尝试以下操作:

 using System.Security.Principal private List<string> GetGroups(string userName) { List<string> result = new List<string>(); WindowsIdentity wi = new WindowsIdentity(userName); foreach (IdentityReference group in wi.Groups) { try { result.Add(group.Translate(typeof(NTAccount)).ToString()); } catch (Exception ex) { } } result.Sort(); return result; } 

我使用try/catch因为在一个非常大的AD中,有200个组中有2个出现exception,因为有些SID不再可用。 ( Translate()调用执行SID – > Name转换。)

首先,GetAuthorizationGroups()是一个很好的function,但不幸的是有两个缺点:

  1. 性能差,特别是在有大量用户和群体的大公司中。 它获取更多的数据,然后实际需要,并为结果中的每个循环迭代进行服务器调用
  2. 它包含的错误可能会导致您的应用程序在“组织和用户不断发展”的某一天停止工作。 微软认识到这个问题,并与一些SID有关。 你会得到的错误是“枚举组时发生错误”

因此,我写了一个小函数来取代GetAuthorizationGroups(),以获得更好的性能和错误安全。 它只用一个使用索引字段的查询进行一次LDAP调用。 如果你需要更多的属性而不仅仅是组名(“cn”属性),它可以很容易地扩展。

 // Usage: GetAdGroupsForUser2("domain\user") or GetAdGroupsForUser2("user","domain") public static List<string> GetAdGroupsForUser2(string userName, string domainName = null) { var result = new List<string>(); if (userName.Contains('\\') || userName.Contains('/')) { domainName = userName.Split(new char[] { '\\', '/' })[0]; userName = userName.Split(new char[] { '\\', '/' })[1]; } using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domainName)) using (UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, userName)) using (var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domainContext.Name))) { searcher.Filter = String.Format("(&(objectCategory=group)(member={0}))", user.DistinguishedName); searcher.SearchScope = SearchScope.Subtree; searcher.PropertiesToLoad.Add("cn"); foreach (SearchResult entry in searcher.FindAll()) if (entry.Properties.Contains("cn")) result.Add(entry.Properties["cn"][0].ToString()); } return result; } 

在AD内,每个用户都有一个属性memberOf 。 这包含他所属的所有组的列表。

这是一个小小的代码示例:

 // (replace "part_of_user_name" with some partial user name existing in your AD) var userNameContains = "part_of_user_name"; var identity = WindowsIdentity.GetCurrent().User; var allDomains = Forest.GetCurrentForest().Domains.Cast<Domain>(); var allSearcher = allDomains.Select(domain => { var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domain.Name)); // Apply some filter to focus on only some specfic objects searcher.Filter = String.Format("(&(&(objectCategory=person)(objectClass=user)(name=*{0}*)))", userNameContains); return searcher; }); var directoryEntriesFound = allSearcher .SelectMany(searcher => searcher.FindAll() .Cast<SearchResult>() .Select(result => result.GetDirectoryEntry())); var memberOf = directoryEntriesFound.Select(entry => { using (entry) { return new { Name = entry.Name, GroupName = ((object[])entry.Properties["MemberOf"].Value).Select(obj => obj.ToString()) }; } }); foreach (var item in memberOf) { Debug.Print("Name = " + item.Name); Debug.Print("Member of:"); foreach (var groupName in item.GroupName) { Debug.Print(" " + groupName); } Debug.Print(String.Empty); } } 

在我的情况下,我可以继续使用GetGroups()没有任何expression式的唯一方法是将用户(USER_WITH_PERMISSION)添加到有权读取AD(Active Directory)的组。 构造传递这个用户和密码的PrincipalContext是非常重要的。

 var pc = new PrincipalContext(ContextType.Domain, domain, "USER_WITH_PERMISSION", "PASS"); var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, userName); var groups = user.GetGroups(); 

您可以在Active Directory中遵循以下步骤来执行这些步骤:

  1. 进入Active Directory创build一个组(或采取一个),并在安全标签下添加“Windows授权访问组”
  2. 点击“高级”button
  3. select“Windows授权访问组”,然后点击“查看”
  4. 选中“读取tokenGroupsGlobalAndUniversal”
  5. find所需的用户并添加到您从第一步创build(采取)的组