C# 如何在ActiveDirectory和.NET3.5中确定用户所属的所有组(包括嵌套组)

C# 如何在ActiveDirectory和.NET3.5中确定用户所属的所有组(包括嵌套组),c#,.net-3.5,active-directory,directoryservices,C#,.net 3.5,Active Directory,Directoryservices,我有一个使用ActiveDirectry授权的应用程序,并且已经决定它需要支持嵌套的广告组,例如: MAIN_AD_GROUP | |-> SUB_GROUP | |-> User 因此,用户不能直接成为MAIN\u AD\u组的成员。我希望能够递归地查找用户,搜索嵌套在MAIN\u AD\u GROUP中的组 主要问题是,我使用的是.NET 3.5,而.NET 3.5中的System.Directory

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

MAIN_AD_GROUP
     |
     |-> SUB_GROUP
              | 
              |-> User
因此,用户不能直接成为
MAIN\u AD\u组的成员。我希望能够递归地查找用户,搜索嵌套在
MAIN\u AD\u GROUP
中的组

主要问题是,我使用的是.NET 3.5,而.NET 3.5中的
System.DirectoryServices.AccountManagement
中存在一个bug,因此
UserPrincipal.IsMemberOf()方法将无法用于用户数超过1500的组。所以我不能使用
UserPrincipal.IsMemberOf()
,也不能切换到.NET4

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

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()
只返回用户是其直接成员的组


如何使其与嵌套组一起工作?

使用
UserPrincipal.GetAuthorizationGroups()
,而不是从其:

此方法搜索所有组 递归地并返回 用户是其中的一个成员。这个 返回的集合还可能包括 该系统将支持的其他组 考虑用户的成员 授权目的

此操作返回的组 方法可以包括来自 不同于 校长。例如,如果 主体是一个具有 一群 “CN=SpecialGroup,DC=Fabrikam,DC=com, 返回的集合可以包含组 属于 “CN=NormalGroups,DC=Fabrikam,DC=com

解决办法#1 通过手动迭代
PrincipalSearchResult
返回的对象,捕获此异常并继续,报告此错误以及以下解决此问题的代码:

PrincipalSearchResult<Principal> 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;
        }
    }
}

有效的方法是通过使用正确的DirectorySearcher筛选器来执行单个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;
    }
你需要用广告中正确的值替换域名和组名

资料来源:


需要包括使用System.DirectoryServices的

我知道这是一个旧的线程,但它是Google上的最高结果,因此,如果这对任何人都有帮助,下面是我使用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;
    }
}

谢谢,但不幸的是,这会引发一个
PrincipalOperationException
异常,并显示消息“服务器上没有这样的对象”。UserPrincipal肯定存在,因为我上面的方法确实返回顶级组的正确授权。
UserPrincipal.GetAuthorizationGroups()
如果存在用户仍然是其成员的已删除组,则会被阻塞。只需检查组名是否不为空,在这种情况下@jprochI选择实施变通办法#2。YMMV的解决方案#1.好帖子。解决方案#1在iterGroup.MoveNext()上失败,并出现相同的错误“服务器上没有此类对象”。只有当程序从登录到域的计算机上运行时,解决方案2才能工作。如果您从其他域查询ldap,则无法使用它。@Kiquenet&@Ronen看起来您可以为
DirectoryEntry domainConnection
使用另一个构造函数来传递在不同域上有效的用户名和密码。请参阅:我编辑了答案以包含一行可用于连接到远程域的代码:
DirectoryEntry domainConnection=newdirectoryEntry(“LDAP://example.com”、“username”、“password”);/使用此选项查询远程域
此原样回答将始终返回true(假设返回前的行中有一个membership=true)
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;
    }
}