如何在ActiveDirectory和.NET 3.5中确定用户所属的所有组(包括嵌套组)

我有一个使用ActiveDirecotry授权的应用程序,并且已经决定它需要支持嵌套的AD组,例如:

MAIN_AD_GROUP | |-> SUB_GROUP | |-> User 

因此,用户不直接成为MAIN_AD_GROUP的成员。 我希望能够递归地查找用户,搜索嵌套在MAIN_AD_GROUP的组。

主要问题是我使用的是.NET 3.5,并且.NET 3.5中的System.DirectoryServices.AccountManagement存在一个错误,即UserPrincipal.IsMemberOf()方法UserPrincipal.IsMemberOf() 用于超过1500个用户的组 。 所以我不能使用UserPrincipal.IsMemberOf()而不是,我也无法切换到.NET 4。

我用以下函数解决了这个最后一个问题:

 private bool IsMember(Principal userPrincipal, Principal groupPrincipal) { using (var groups = userPrincipal.GetGroups()) { var isMember = groups.Any(g => g.DistinguishedName == groupPrincipal.DistinguishedName); return isMember; } } 

userPrincipal.GetGroups()仅返回用户是其直接成员的组。

如何使用嵌套组?

解决方法#1

此错误在Microsoft Connect中报告,以及通过手动迭代PrincipalSearchResult返回的对象,捕获此exception并继续执行以下代码解决此问题的以下代码:

 PrincipalSearchResult groups = user.GetAuthorizationGroups(); var iterGroup = groups.GetEnumerator(); using (iterGroup) { while (iterGroup.MoveNext()) { try { Principal p = iterGroup.Current; Console.WriteLine(p.Name); } catch (NoMatchingPrincipalException pex) { continue; } } } 

解决方法#2

此处找到的另一个解决方法是避免使用AccountManagement类,而是使用System.DirectoryServices API:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.DirectoryServices; namespace GetGroupsForADUser { class Program { static void Main(string[] args) { String username = "Gabriel"; List userNestedMembership = new List(); DirectoryEntry domainConnection = new DirectoryEntry(); // Use this to query the default domain //DirectoryEntry domainConnection = new DirectoryEntry("LDAP://example.com", "username", "password"); // Use this to query a remote domain DirectorySearcher samSearcher = new DirectorySearcher(); samSearcher.SearchRoot = domainConnection; samSearcher.Filter = "(samAccountName=" + username + ")"; samSearcher.PropertiesToLoad.Add("displayName"); SearchResult samResult = samSearcher.FindOne(); if (samResult != null) { DirectoryEntry theUser = samResult.GetDirectoryEntry(); theUser.RefreshCache(new string[] { "tokenGroups" }); foreach (byte[] resultBytes in theUser.Properties["tokenGroups"]) { System.Security.Principal.SecurityIdentifier mySID = new System.Security.Principal.SecurityIdentifier(resultBytes, 0); DirectorySearcher sidSearcher = new DirectorySearcher(); sidSearcher.SearchRoot = domainConnection; sidSearcher.Filter = "(objectSid=" + mySID.Value + ")"; sidSearcher.PropertiesToLoad.Add("distinguishedName"); SearchResult sidResult = sidSearcher.FindOne(); if (sidResult != null) { userNestedMembership.Add((string)sidResult.Properties["distinguishedName"][0]); } } foreach (string myEntry in userNestedMembership) { Console.WriteLine(myEntry); } } else { Console.WriteLine("The user doesn't exist"); } Console.ReadKey(); } } } 

使用UserPrincipal.GetAuthorizationGroups() – 来自其MSDN文档 :

此方法以递归方式搜索所有组,并返回用户所属的组。 返回的集合还可以包括系统将用户视为授权目的的其他组。

此方法返回的组可能包括来自与主体不同的范围和存储的组。 例如,如果主体是AD DS对象,其DN为“CN = SpecialGroups,DC = Fabrikam,DC = com,则返回的集合可以包含属于”CN = NormalGroups,DC = Fabrikam,DC =的组COM。

我知道这是一个老线程,但它是谷歌的最佳结果,所以如果这有助于任何人,这就是我提出的使用AccountManagement的东西,但使这个特定的查询更容易。

 public static class AccountManagementExtensions { public static bool IsNestedMemberOf(this Principal principal, GroupPrincipal group) { // LDAP Query for memberOf Nested var filter = String.Format("(&(sAMAccountName={0})(memberOf:1.2.840.113556.1.4.1941:={1}))", principal.SamAccountName, group.DistinguishedName ); var searcher = new DirectorySearcher(filter); var result = searcher.FindOne(); return result != null; } } 

有效的方法是通过使用正确的DirectorySearcherfilter来执行单个AD查询

 public bool CheckMemberShip(string userName) { bool membership = false; string connection = "LDAP://"+YOURDOMAIN; DirectoryEntry entry = new DirectoryEntry(connection); DirectorySearcher mySearcher = new DirectorySearcher(entry); mySearcher.Filter = "(&(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=cn=GROUPNAME,OU=Groups,OU=ABC,OU=ABC,OU=IND,DC=ad,DC=COMPANY,DC=com)(|(sAMAccountName=" + userName + ")))"; SearchResult result = mySearcher.FindOne(); // No search result, hence no membership if (result == null) { membership = false; } entry.Close(); entry.Dispose(); mySearcher.Dispose(); membership = true; return membership; } 

您需要使用AD中的正确值替换YOURDOMAIN和GROUPNAME。

来源: 如何使用.NET / C#和LDAP递归获取Active Directory中用户的组成员身份(不仅仅有2次点击Active Directory)

需要包含using System.DirectoryServices;