【问题标题】:Best way to quickly determine whether a user account is a member of an AD group?快速确定用户帐户是否是 AD 组成员的最佳方法?
【发布时间】:2008-12-15 16:02:27
【问题描述】:

我目前有一些代码可以下拉组中的用户列表,然后遍历该组以确定给定帐户是否存在,但似乎应该有一种更简洁(也许更快)的方法来完成这个。

此代码 (VB.NET) 尝试使用组对象的成员属性,但即使用户是该组的成员,它也会返回 false。谁能看到我在这里做错了什么?

Dim group As DirectoryEntry =  GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName)
Dim user As DirectoryEntry =GetNetworkObject(UserDomainName, NetworkObjectType.NetworkUser, Login)

Return group.Properties("member").Contains(user.Path)

仅供参考:GetNetworkObject 调用仅返回一个 directoryEntry 对象,我已确认为组和用户对象返回了正确的对象。

【问题讨论】:

    标签: active-directory ldap adsi directoryentry


    【解决方案1】:

    如果您使用 .NET 3.5 堆栈,System.DirectoryServices.AccountManagement.dll assembly 在 AD 之上有一个不错的 API。可以实施以下方法来解决您的问题:

    static bool IsUserMemberOf(string userName, string groupName)
    {
        using (var ctx = new PrincipalContext(ContextType.Domain))
        using (var groupPrincipal = GroupPrincipal.FindByIdentity(ctx, groupName))
        using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, userName))
        {
            return userPrincipal.IsMemberOf(groupPrincipal);
        }
    }
    
    // Usage:
    bool result = IsUserMemberOf("CONTOSO\\john.doe", "CONTOSO\\Administrators");
    

    我不知道这种方法的效果如何,但它是一个干净的解决方案。

    【讨论】:

    • 谢谢。我什至没有意识到 3.5 为 AD 添加了(非常需要的)抽象层。我会给你一个答案,因为它很棒,但是我的部署环境仍然是 NET 2.0。
    【解决方案2】:

    这是我过去在一个运行良好的 VBS 脚本中使用的:

    Set wshNet = CreateObject("WScript.Network")                'Setup connection to the Network
    Set fso = CreateObject("Scripting.FileSystemObject")        'Create File System Object for any file manipulations
    
    Set ADSysInfo = CreateObject("ADSystemInfo")                'Setup connection to Active Directory
    Set CurrentUser = GetObject("LDAP://" & ADSysInfo.UserName) 'Setup current user to look for in Active Directory
    strGroups = LCase(Join(CurrentUser.MemberOf))               'Grabs all the groups the current user is a member of
    

    然后我使用 InStr 来查看用户是否属于该组:

    If InStr(strGroups, "MyGroup") Then MyGroupSub
    

    您也许可以在您的项目中调整上述内容。

    顺便说一句,我注意到在您的代码中,您将 groupdoman 作为 'group' 的最后一个参数 不确定您是否希望它是 groupdomain 与否:

    Dim group As DirectoryEntry = GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName, groupdoman)

    Dim group As DirectoryEntry = GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName, groupdomain)

    如果这有帮助,请告诉我!捷豹路虎

    【讨论】:

    • 很好地了解 groupdomain 参数。实际上,那是一些与我只删除了一半的问题无关的代码的一部分(哎呀,现在已修复)它允许我为组传递 OU。
    【解决方案3】:

    我找到了一个似乎在 NET 2.0 中有效的答案,相对较快,并且克服了包含超过 100 个项目的组的可能问题(需要范围搜索)

    这是我最终得到的代码:

    Dim DSearcher As New DirectorySearcher(group, "(&(objectClass=user)(cn=" + Login + "))", New String() {"member;Range=0-5000"}, SearchScope.OneLevel)                  
    group = GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName)
    user = GetNetworkObject(UserDomainName, NetworkObjectType.NetworkUser, Login)
    DSearcher.AttributeScopeQuery = "member"
    Return (DSearcher.FindOne() IsNot Nothing)
    

    【讨论】:

    • 请注意。完成测试后,我将调整此条目,但我发现它在两种情况下失败:1)如果用户存在于组中,但来自另一个受信任的林。 2) 如果一个同名但不同域的用户是该组的成员。
    【解决方案4】:

    这是使用目录搜索器和 memberOf 的另一种方式。这是使用当前用户的 objectSID,但您可以将其更改为其他标识符。

    dSearch.Filter = String.Format("(&(memberOf={0})(objectSid={1}))", groupDN, WindowsIdentity.GetCurrent.User)
    
    Return dSearch.FindOne() IsNot Nothing
    

    如果您要使用可能包含无效字符的用户输入,则应始终对其进行转义...

    searchName = searchName.Replace("\", "\5c"). _
                                    Replace("/", "\2f"). _
                                    Replace("*", "\2a"). _
                                    Replace("(", "\28"). _
                                    Replace(")", "\29")
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-27
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    相关资源
    最近更新 更多