如何在Active Directory中获取用户组?(c#,asp.net)

Tas*_*sto 103 c# asp.net active-directory

我使用此代码来获取当前用户的组.但我想手动给用户,然后得到他的组.我怎样才能做到这一点?

using System.Security.Principal;

public ArrayList Groups()
{
    ArrayList groups = new ArrayList();

    foreach (IdentityReference group in System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups)
    {
        groups.Add(group.Translate(typeof(NTAccount)).ToString());
    }

    return groups;
}
Run Code Online (Sandbox Code Playgroud)

mar*_*c_s 155

如果您使用的是.NET 3.5或更高版本,则可以使用新的System.DirectoryServices.AccountManagement(S.DS.AM)命名空间,这使得它比以前容易得多.

阅读所有相关内容:在.NET Framework 3.5中管理目录安全性主体

更新:旧的MSDN杂志文章不再在线,不幸的是 - 你需要从微软下载2008年1月的MSDN杂志的CHM并阅读那里的文章.

基本上,您需要拥有"主要上下文"(通常是您的域),用户主体,然​​后您可以非常轻松地获得其组:

public List<GroupPrincipal> GetGroups(string userName)
{
   List<GroupPrincipal> result = new List<GroupPrincipal>();

   // establish domain context
   PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);

   // find your user
   UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName);

   // if found - grab its groups
   if(user != null)
   {
      PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();

      // iterate over all groups
      foreach(Principal p in groups)
      {
         // make sure to add only group principals
         if(p is GroupPrincipal)
         {
             result.Add((GroupPrincipal)p);
         }
      }
   }

   return result;
}
Run Code Online (Sandbox Code Playgroud)

这就是全部!您现在拥有用户所属的授权组的结果(列表) - 迭代它们,打印出它们的名称或您需要做的任何事情.

更新:为了访问未在UserPrincipal对象上显示的某些属性,您需要深入了解底层DirectoryEntry:

public string GetDepartment(Principal principal)
{
    string result = string.Empty;

    DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry);

    if (de != null)
    {
       if (de.Properties.Contains("department"))
       {
          result = de.Properties["department"][0].ToString();
       }
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

更新#2:似乎不应该太难将这两段代码放在一起....但是好的 - 这就是:

public string GetDepartment(string username)
{
    string result = string.Empty;

    // if you do repeated domain access, you might want to do this *once* outside this method, 
    // and pass it in as a second parameter!
    PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);

    // find the user
    UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username);

    // if user is found
    if(user != null)
    {
       // get DirectoryEntry underlying it
       DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry);

       if (de != null)
       {
          if (de.Properties.Contains("department"))
          {
             result = de.Properties["department"][0].ToString();
          }
       }
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案很棒。也可以将组迭代简化为: result.AddRange(user.GetAuthorizationGroups().OfType&lt;GroupPrincipal&gt;() (2认同)

Mic*_*use 56

GetAuthorizationGroups()找不到嵌套组.要真正获取给定用户的所有组是(包括嵌套组)的成员,请尝试以下操作:

using System.Security.Principal

private List<string> GetGroups(string userName)
{
    List<string> result = new List<string>();
    WindowsIdentity wi = new WindowsIdentity(userName);

    foreach (IdentityReference group in wi.Groups)
    {
        try
        {
            result.Add(group.Translate(typeof(NTAccount)).ToString());
        }
        catch (Exception ex) { }
    }
    result.Sort();
    return result;
}
Run Code Online (Sandbox Code Playgroud)

我使用try/catch是因为我在一个非常大的AD中有200个组中的2个有一些例外,因为一些SID不再可用.(该Translate()调用执行SID - >名称转换.)

  • 通过使用这种技术而不是通过AD来改善性能.谢谢! (3认同)

Big*_*jim 16

首先,GetAuthorizationGroups()是一个很棒的函数,但不幸的是有两个缺点:

  1. 性能很差,尤其是在拥有众多用户和群体的大公司中.它会获取您实际需要的更多数据,并在结果中为每个循环迭代执行服务器调用
  2. 它包含的错误可能会导致您的应用程序在组和用户不断发展的"某一天"停止工作.Microsoft认识到了这个问题并且与某些SID有关.您将得到的错误是"枚举组时出错"

因此,我编写了一个小函数来替换具有更好性能和错误安全性的GetAuthorizationGroups().它只使用索引字段进行一次LDAP调用.如果您需要的属性多于组名("cn"属性),则可以轻松扩展它.

// Usage: GetAdGroupsForUser2("domain\user") or GetAdGroupsForUser2("user","domain")
public static List<string> GetAdGroupsForUser2(string userName, string domainName = null)
{
    var result = new List<string>();

    if (userName.Contains('\\') || userName.Contains('/'))
    {
        domainName = userName.Split(new char[] { '\\', '/' })[0];
        userName = userName.Split(new char[] { '\\', '/' })[1];
    }

    using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domainName))
        using (UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, userName))
            using (var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domainContext.Name)))
            {
                searcher.Filter = String.Format("(&(objectCategory=group)(member={0}))", user.DistinguishedName);
                searcher.SearchScope = SearchScope.Subtree;
                searcher.PropertiesToLoad.Add("cn");

                foreach (SearchResult entry in searcher.FindAll())
                    if (entry.Properties.Contains("cn"))
                        result.Add(entry.Properties["cn"][0].ToString());
            }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

  • 这似乎很有希望,但它不能解析嵌套组,例如用户是组a的成员,组本身是组x的成员.上面的代码只显示组a,但不显示组x.我通过tokenGroups使用了这个方法:http://stackoverflow.com/a/4460658/602449 (3认同)

Oli*_*ver 10

在AD中,每个用户都有一个属性memberOf.这包含他所属的所有组的列表.

这是一个小代码示例:

// (replace "part_of_user_name" with some partial user name existing in your AD)
var userNameContains = "part_of_user_name";

var identity = WindowsIdentity.GetCurrent().User;
var allDomains = Forest.GetCurrentForest().Domains.Cast<Domain>();

var allSearcher = allDomains.Select(domain =>
{
    var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domain.Name));

    // Apply some filter to focus on only some specfic objects
    searcher.Filter = String.Format("(&(&(objectCategory=person)(objectClass=user)(name=*{0}*)))", userNameContains);
    return searcher;
});

var directoryEntriesFound = allSearcher
    .SelectMany(searcher => searcher.FindAll()
        .Cast<SearchResult>()
        .Select(result => result.GetDirectoryEntry()));

var memberOf = directoryEntriesFound.Select(entry =>
{
    using (entry)
    {
        return new
        {
            Name = entry.Name,
            GroupName = ((object[])entry.Properties["MemberOf"].Value).Select(obj => obj.ToString())
        };
    }
});

foreach (var item in memberOf)
{
    Debug.Print("Name = " + item.Name);
    Debug.Print("Member of:");

    foreach (var groupName in item.GroupName)
    {
        Debug.Print("   " + groupName);
    }

    Debug.Print(String.Empty);
}
}
Run Code Online (Sandbox Code Playgroud)

  • 它将无法列出用户的主要组(通常是域用户).您必须单独返回并查询该信息.GetAuthorizationGroups没有此问题. (2认同)

小智 5

我的解决方案:

UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain, myDomain), IdentityType.SamAccountName, myUser);
List<string> UserADGroups = new List<string>();            
foreach (GroupPrincipal group in user.GetGroups())
{
    UserADGroups.Add(group.ToString());
}
Run Code Online (Sandbox Code Playgroud)