在C# + Asp.net中查看用户是否属于Active Directory组

51

我需要一种方法来检查我的.Net 3.5 asp.net c#应用程序中的用户是否属于一个活动目录组。

我正在使用msdn上的标准ldap身份验证示例,但我不知道如何检查组成员资格。

15个回答

41

使用3.5和System.DirectoryServices.AccountManagement会更加简洁:

public List<string> GetGroupNames(string userName)
{
  var pc = new PrincipalContext(ContextType.Domain);
  var src = UserPrincipal.FindByIdentity(pc, userName).GetGroups(pc);
  var result = new List<string>();
  src.ToList().ForEach(sr => result.Add(sr.SamAccountName));
  return result;
}

我在列出的代码上遇到了这个错误:未知错误(0x80005000) 描述:当前 Web 请求执行期间发生未处理的异常。请查看堆栈跟踪以获取有关错误的更多信息以及其在代码中的起源。 异常详细信息:System.Runtime.InteropServices.COMException: 未知错误(0x80005000)引起此错误的行是:"var src = UserPrincipal.FindByIdentity(pc, userName).GetGroups(pc);"您有什么建议吗?我将函数原封不动地从您的示例中复制了过来。 - Ben
1
@Ben,你确定你使用的账户有权限查询 AD 吗?许多地方禁用了匿名绑定。 - Nick Craver
12
我正在使用.NET 4.0版本。我不得不更改这行代码:var pc = new PrincipalContext(ContextType.Domain);,改为 var pc = new PrincipalContext(ContextType.Domain, "MyDomainHere") 来消除异常。之后程序完美运行。 - Dan
1
@NickCraver 为什么你没有处理 PrincipalContext 和 UserPrincipal 的释放? - Mathematics

20

Nick Craver的解决方案在我的.NET 4.0中不起作用。我收到一个有关未装入的AppDomain的错误。相反,我使用了以下解决方案(我们只有一个域)。这将检查组的组以及直接组成员资格。

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

...

using (var ctx = new PrincipalContext(ContextType.Domain, yourDomain)) {
    using (var grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, yourGroup)) {
        bool isInRole = grp != null && 
            grp
            .GetMembers(true)
            .Any(m => m.SamAccountName == me.Identity.Name.Replace(yourDomain + "\\", ""));
    }
}

当我使用这段代码时,.Any() 方法出现编译错误,提示没有扩展方法。我需要添加其他的 using 或 reference 吗? - Anto Varghese
1
@Antoops - 你需要为 System.Linq 添加一个 using 语句。 - David McClelland
+1 是因为展示了如何使用 GetMembers(true),这正是我需要递归检查组成员的方法! - David McClelland

16

以下代码适用于 .net 4.0

private static string[] GetGroupNames(string userName)
{
    List<string> result = new List<string>();

    using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAIN"))
    {
        using (PrincipalSearchResult<Principal> src = UserPrincipal.FindByIdentity(pc, userName).GetGroups(pc))
        {
            src.ToList().ForEach(sr => result.Add(sr.SamAccountName));
        }
    }

    return result.ToArray();
}

1
好的回答。谢谢。 有几个非常小的修复: 将结果初始化为您想要返回的类型 - 即列表或数组。 用以下内容替换此行: src.ToList().ForEach(sr => result.Add(sr.SamAccountName)); 使用以下内容: result = src.Select(x => x.SamAccountName).ToList(); //如果您喜欢,可以使用ToArray - user3230660

10

最简单的解决方案

PrincipalContext pc = new PrincipalContext((Environment.UserDomainName == Environment.MachineName ? ContextType.Machine : ContextType.Domain), Environment.UserDomainName);

GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, "{GroupName}");
UserPrincipal up = UserPrincipal.FindByIdentity(pc, Environment.UserName);
up.IsMemberOf(gp);

7

如果您正在尝试确定Windows身份验证的当前用户是否属于特定角色,此方法可能有帮助。

public static bool CurrentUserIsInRole(string role)
{
    try
    {
        return System.Web.HttpContext.Current.Request
                    .LogonUserIdentity
                    .Groups
                    .Any(x => x.Translate(typeof(NTAccount)).ToString() == role);
        }
        catch (Exception) { return false; }
    }

5
这取决于您所说的用户是否在AD组中。在AD中,组可以是安全组或分发组。即使对于安全组,也取决于是否需要包括像“域用户”或“用户”这样的组在成员身份检查中。
IsUserInSecurityGroup仅检查安全组,并且适用于主要组类型的组,例如“域用户”和“用户”,而不是分发组。它还解决了嵌套组的问题。 IsUserInAllGroup还将检查分发组,但我不确定是否会遇到权限问题。如果确实如此,请使用一个在WAAG中的服务帐户(请参见MSDN)。
我不使用UserPrincipal.GetAuthorizedGroups()的原因是它有很多问题,例如需要调用帐户在WAAG中并且需要没有SidHistory条目(请参见David Thomas' comment)。
public bool IsUserInSecurityGroup(string user, string group)
    {
        return IsUserInGroup(user, group, "tokenGroups");
    }
    public bool IsUserInAllGroup(string user, string group)
    {
        return IsUserInGroup(user, group, "tokenGroupsGlobalAndUniversal");
    }

    private bool IsUserInGroup(string user, string group, string groupType)
    {
        var userGroups = GetUserGroupIds(user, groupType);
        var groupTokens = ParseDomainQualifiedName(group, "group");
        using (var groupContext = new PrincipalContext(ContextType.Domain, groupTokens[0]))
        {
            using (var identity = GroupPrincipal.FindByIdentity(groupContext, IdentityType.SamAccountName, groupTokens[1]))
            {
                if (identity == null)
                    return false;

                return userGroups.Contains(identity.Sid);
            }
        }
    }
    private List<SecurityIdentifier> GetUserGroupIds(string user, string groupType)
    {
        var userTokens = ParseDomainQualifiedName(user, "user");
        using (var userContext = new PrincipalContext(ContextType.Domain, userTokens[0]))
        {
            using (var identity = UserPrincipal.FindByIdentity(userContext, IdentityType.SamAccountName, userTokens[1]))
            {
                if (identity == null)
                    return new List<SecurityIdentifier>();

                var userEntry = identity.GetUnderlyingObject() as DirectoryEntry;
                userEntry.RefreshCache(new[] { groupType });
                return (from byte[] sid in userEntry.Properties[groupType]
                        select new SecurityIdentifier(sid, 0)).ToList();
            }
        }
    }
    private static string[] ParseDomainQualifiedName(string name, string parameterName)
    {
        var groupTokens = name.Split(new[] {"\\"}, StringSplitOptions.RemoveEmptyEntries);
        if (groupTokens.Length < 2)
            throw new ArgumentException(Resources.Exception_NameNotDomainQualified + name, parameterName);
        return groupTokens;
    }

所有其他答案对我来说都是错误的,因为它们没有考虑到嵌套组。谢谢。 - Thibault D.

3
这似乎更简单:
public bool IsInRole(string groupname)
{
    var myIdentity = WindowsIdentity.GetCurrent();
    if (myIdentity == null) return false;

    var myPrincipal = new WindowsPrincipal(myIdentity);
    var result = myPrincipal.IsInRole(groupname);

    return result;
}

3

以下是我的两分意见。

    static void CheckUserGroup(string userName, string userGroup)
    {
        var wi = new WindowsIdentity(userName);
        var wp = new WindowsPrincipal(wi);

        bool inRole = wp.IsInRole(userGroup);

        Console.WriteLine("User {0} {1} member of {2} AD group", userName, inRole ? "is" : "is not", userGroup);
    }

2
您可以尝试以下代码:

public bool Check_If_Member_Of_AD_Group(string username, string grouptoCheck, string domain, string ADlogin, string ADpassword)
{
    
     try {
        
        string EntryString = null;
        EntryString = "LDAP://" + domain;
        
        DirectoryEntry myDE = default(DirectoryEntry);
        
        grouptoCheck = grouptoCheck.ToLower();
        
        
        myDE = new DirectoryEntry(EntryString, ADlogin, ADpassword);
        
        DirectorySearcher myDirectorySearcher = new DirectorySearcher(myDE);
        
        myDirectorySearcher.Filter = "sAMAccountName=" + username;
        
        myDirectorySearcher.PropertiesToLoad.Add("MemberOf");
        
        SearchResult myresult = myDirectorySearcher.FindOne();
        
        int NumberOfGroups = 0;
        
        NumberOfGroups = myresult.Properties["memberOf"].Count - 1;
        
        string tempString = null;
        
        while ((NumberOfGroups >= 0)) {
            
            tempString = myresult.Properties["MemberOf"].Item[NumberOfGroups];
            tempString = tempString.Substring(0, tempString.IndexOf(",", 0));
            
            tempString = tempString.Replace("CN=", "");
            
            tempString = tempString.ToLower();
            tempString = tempString.Trim();
            
            if ((grouptoCheck == tempString)) {
                
                    
                return true;
            }
            
                
            NumberOfGroups = NumberOfGroups - 1;
        }
        
            
        return false;
    }
    catch (Exception ex) {
        
        System.Diagnostics.Debugger.Break();
    }
    //HttpContext.Current.Response.Write("Error: <br><br>" & ex.ToString)
}

2
与BC的答案一样,上述代码不会测试嵌套成员资格。 - Mick Walker


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