如何检查用户是否属于AD组?

68

一开始我认为以下代码可以工作,因为如果我的组是"IT",它会正确地运行,因为在活动目录中我的用户名属于IT组。但我发现无论我是否将我的用户名添加到IT组中,它始终返回true,如果我将其更改为我所在的任何其他组,它始终返回false。希望能得到任何帮助。

    private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
    {
        // tab control security for admin tab
        bool admin = checkGroup("IT");

        if ((admin == true) && (tabControl1.SelectedTab == tpHistory))
        {
            tabControl1.SelectedTab = tpHistory;
        }
        else if ((admin == false) && (tabControl1.SelectedTab == tpHistory))
        {
            tabControl1.SelectedTab = tpRequests;
            MessageBox.Show("Unable to load tab. You have insufficient privileges.",
                "Access Denied", MessageBoxButtons.OK, MessageBoxIcon.Stop);
        }
    }

    // check active directory to see if user is in Marketing department group
    private static bool checkGroup(string group)
    {
        WindowsIdentity identity = WindowsIdentity.GetCurrent();
        WindowsPrincipal principal = new WindowsPrincipal(identity);
        return principal.IsInRole(group);
    }
6个回答

138

如果您使用的是 .NET 3.5 或更高版本,您应该查看 System.DirectoryServices.AccountManagement (S.DS.AM) 命名空间。在这里阅读有关此命名空间的所有内容:

基本上,您可以定义一个域上下文,并轻松地在 AD 中查找用户和/或组:

// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "DOMAINNAME");

// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");

// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "YourGroupNameHere");

if(user != null)
{
   // check if user is member of that group
   if (user.IsMemberOf(group))
   {
     // do something.....
   } 
}

新的 S.DS.AM 使得在 AD 中玩弄用户和组变得非常容易!


1
显然这是4.0版本中的一个错误http://social.msdn.microsoft.com/Forums/pl-PL/csharplanguage/thread/4c9fea6c-1d0a-4733-a8ac-e3b78d10e999,我通过将Environment.UserDomainName添加到原则上下文中来修复它。https://dev59.com/2W855IYBdhLWcg3wIAka 如果你想在你的代码中编辑它,我会接受你的答案。非常感谢你的帮助! - Sealer_05
1
@osiris355:我在 social.msdn 的帖子中更新了我的回复,并提供了解决方法。 - marc_s
1
这是一份很好的指南。我能够将其转换为几行PowerShell代码,以便更方便地使用API。我已经在这篇博客文章中记录了它。 - KFL
这段代码在部署到IIS后无法正常工作,请给予建议。 - Saurabh
注意:此方法将确定用户是否为精确组的成员,但无法确定是否属于嵌套组。在这种情况下,请查看https://stackoverflow.com/q/10145781/685。 - undefined
显示剩余6条评论

14

稍微有所不同于 @marc_s 的示例,在 Program 类的 static void Main() 方法中实现:

Translated text:

与 @marc_s 示例稍有不同,在 Program 类的 static void Main() 方法中实现:

DomainCtx = new PrincipalContext( ContextType.Domain , Environment.UserDomainName );
if ( DomainCtx != null ) {
    User = UserPrincipal.FindByIdentity( DomainCtx , Environment.UserName );
}
< p > DomainCtxUser都是在Program下声明的静态属性。

然后在其他表单中,我只需像这样做:

if ( Program.User.IsMemberOf(GroupPrincipal.FindByIdentity(Program.DomainCtx, "IT-All") )) {
    //Enable certain Form Buttons and objects for IT Users

}

0
检查当前用户是否在一个组中。
public bool AuthenticateGroup(string groupfind)
        {
            var p = new Process();
            StringBuilder stringbd = new StringBuilder();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.Arguments = @"/c gpresult /V";
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardInput = false;
            p.StartInfo.UseShellExecute = false;
            p.OutputDataReceived += (a, b) => stringbd.AppendLine(b.Data);
            p.ErrorDataReceived += (a, b) => stringbd.AppendLine(b.Data);
            p.Start();
            p.BeginErrorReadLine();
            p.BeginOutputReadLine();
            p.WaitForExit();
            var textfind = stringbd.ToString();
            int findpoint = textfind.IndexOf("The user is a part of");
            string findgroup = "";
            if (findpoint > 0)
            {
                findgroup = textfind.Substring(findpoint, textfind.Length - findpoint);
            }

            return findgroup.Split('\n').ToList().Any(r=>r.Trim().ToLower()==groupfind.Trim().ToLower());
        }

使用 whoami /groups 命令可以更快地获取结果。 - Danny Sotzny
启动一个完整的额外进程非常昂贵,并且有很多注意事项。这种特定解决方案的方式可能是最昂贵、最慢和最有潜在危险的方式,以实现这个已经非常次优的解决方案。没有人应该这样做,因为在每个版本的.net上都有内置的方法来获取AD组。另外,如果无论如何都要这样做,为什么不在OutputDataReceived事件中检查每个返回的字符串,然后终止,而不是构建一个可能非常庞大的字符串,然后搜索它呢? - undefined

0

3
尽管这种方法相对较为繁琐,但利用 IIS 提供的 WindowsIdentity 可以使用用户配置文件中加载的当前标记,无需查询 AD Forest/Node 即可获取已经本地加载的相同信息。 - GoldBishop

0
为什么不这样写:

bool isUserInGroup = HttpContext.User.IsInRole(".nameOfAdGroup");


IsInRole的功能完美运作,但我们的Active Directory中有大约20万个用户/计算机对象,如果有很多用户同时调用此功能,域控制器会明显变慢。 我的解决方案可以解决这个问题,因为我不知道微软在内部是如何处理IsInRole的。 - Mickey Mouse

0

我有一个完美的解决方案,具有错误处理功能,而且可以自动处理子组,无需循环扫描所有子组。IsMemberOf 不适用于子组。因此,你必须使用这个:

LDAP_MATCHING_RULE_IN_CHAIN

using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;

public static bool IsUserInGroup(string userName, string groupName)
{
    try
    {
        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
        {
            var gp = GroupPrincipal.FindByIdentity(pc, groupName);
            var up = UserPrincipal.FindByIdentity(pc, userName);

            if (gp == null) throw new ApplicationException($"Group '{groupName}' not found in Active Directory");
            if (up == null) throw new ApplicationException($"User '{userName}' not found in Active Directory");

            DirectoryEntry user = new DirectoryEntry($"LDAP://{up.DistinguishedName}");
            DirectorySearcher mySearcher = new DirectorySearcher(user)
            {
                SearchScope = SearchScope.Subtree,
                Filter = $"(memberOf:1.2.840.113556.1.4.1941:={gp.DistinguishedName})"  // takes also subgroups
            };

            return !(mySearcher.FindOne() is null);
        }
    }
    catch (Exception)
    {
        throw;
    }
}

public static bool IsComputerInGroup(string computerName, string groupName)
{
    try
    {
        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
        {
            var gp = GroupPrincipal.FindByIdentity(pc, groupName);
            var cp = ComputerPrincipal.FindByIdentity(pc, computerName);

            if (gp == null) throw new ApplicationException($"Group '{groupName}' not found in Active Directory");
            if (cp == null) throw new ApplicationException($"Computer '{computerName}' not found in Active Directory");

            DirectoryEntry computer = new DirectoryEntry($"LDAP://{cp.DistinguishedName}");
            DirectorySearcher mySearcher = new DirectorySearcher(computer)
            {
                SearchScope = SearchScope.Subtree,
                Filter = $"(memberOf:1.2.840.113556.1.4.1941:={gp.DistinguishedName})"
            };

            return !(mySearcher.FindOne() is null);
        }
    }
    catch (Exception)
    {
        throw;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接