如何获取 ActiveDirectory 中的用户组? (c # ,asp.net)

我使用这段代码来获取当前用户的组。但我想手动给用户,然后得到他的组。我怎么能这么做?

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;
}
231553 次浏览

在 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);
}
}

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

点击这里阅读: 在.NET Framework 3.5中管理目录安全原则

更新: 旧的 MSDN 杂志文章已经不在线了,不幸的是——你需要从微软的 download the CHM for the January 2008 MSDN magazine中读到这篇文章。

基本上,你需要一个“主体上下文”(通常是你的域) ,一个用户主体,然后你很容易得到它的组:

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

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

更新: 为了访问某些在 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;
}

更新 # 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;
}

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

我使用 try/catch是因为在一个非常大的 AD 中,有200个组中有2个出现了一些异常,因为一些 SID 不再可用。(Translate()调用执行 SID-> Name 转换。)

在我的例子中,我可以不带任何异常地继续使用 GetGroups ()的唯一方法是将用户(USER _ WITHPERMISION)添加到具有读取 AD (Active Directory)权限的组中。通过这个用户和密码构造 PrincipalContext 是非常必要的。

var pc = new PrincipalContext(ContextType.Domain, domain, "USER_WITH_PERMISSION", "PASS");
var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, userName);
var groups = user.GetGroups();

您可以在 ActiveDirectory 中按照以下步骤使其工作:

  1. 在 ActiveDirectory 中创建一个组(或取一个) ,并在“安全”选项卡下添加“ Windows 授权访问组”
  2. 点击“高级”按钮
  3. 选择“ Windows 授权访问组”,然后单击“查看”
  4. Check "Read tokenGroupsGlobalAndUniversal"
  5. 找到所需的用户,并将其添加到您从第一步创建(获取)的组中

First of all, GetAuthorizationGroups() is a great function but unfortunately has 2 disadvantages:

  1. 性能很差,特别是在拥有许多用户和组的大公司。它获取比您实际需要的更多的数据,并为结果中的每个循环迭代执行一个服务器调用
  2. 它包含一些 bug,当组和用户不断发展时,这些 bug 会导致你的应用程序“某一天”停止工作。微软认识到了这个问题,并且与一些 SID 有关。您将得到的错误是“枚举组时发生错误”

因此,我编写了一个小函数来替换 GetAuthorizationgroups () ,使其具有更好的性能和错误安全性。对于使用索引字段的查询,它只执行1次 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;
}

以防 Translate 在本地工作,但不能远程运行 e.i group. 翻译(类型(NTAccount))

如果希望使用 LOGGEDINUSER 标识执行应用程序代码,则启用模拟。模拟可以通过 IIS 或 在 web.config 中添加以下元素启用。

<system.web>
<identity impersonate="true"/>

如果启用了模拟,应用程序将使用在用户帐户中找到的权限执行。因此,如果登录用户有权访问,特定的网络资源,只有这样,他才能够通过应用程序访问该资源。

感谢 PRAGIM 技术从他勤奋的视频这一信息

在 asp.net 中进行 Windows 身份验证第87部分:

Https://www.youtube.com/watch?v=zftmaz3ysmc

但是模拟会在服务器上造成大量开销

允许特定网络组 的用户的最佳解决方案是在 web 配置中拒绝匿名 <authorization><deny users="?"/><authentication mode="Windows"/>

在后面的代码中,最好是 global.asax 中,使用 当前用户:

Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
If HttpContext.Current.User.IsInRole("TheDomain\TheGroup") Then
//code to do when user is in group
End If

注意: Group 必须用反斜杠写,即“ TheDomain TheGroup”

这对我有用

public string[] GetGroupNames(string domainName, string userName)
{
List<string> result = new List<string>();


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


return result.ToArray();
}

答案取决于要检索的组的类型。System.DirectoryServices.AccountManagement命名空间提供了两个组检索方法:

GetGroups -返回组对象的集合,这些对象指定当前主体是其成员的组。

此重载方法只返回主体直接为其成员的组; 不执行递归搜索。

GetAuthorizationgroups -返回一个主体对象集合,其中包含此用户是其成员的所有授权组。此函数只返回属于安全组的组; 不返回通讯组。

此方法递归地搜索所有组,并返回用户是其成员的组。返回的集合还可能包含其他组,出于授权的目的,系统会将用户视为该组的成员。

因此,GetGroups获取用户是 直接成员的 所有组,而 GetAuthorizationGroups获取用户是 直接的或间接的成员的所有 授权组。

不管它们的命名方式如何,其中一个并不是另一个的子集。可能有由 GetGroups返回的组没有由 GetAuthorizationGroups返回,反之亦然。

下面是一个使用例子:

PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "MyDomain", "OU=AllUsers,DC=MyDomain,DC=Local");
UserPrincipal inputUser = new UserPrincipal(domainContext);
inputUser.SamAccountName = "bsmith";
PrincipalSearcher adSearcher = new PrincipalSearcher(inputUser);
inputUser = (UserPrincipal)adSearcher.FindAll().ElementAt(0);
var userGroups = inputUser.GetGroups();

我的解决办法是:

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());
}

这是快速和肮脏的,但有人可能会发现它的帮助。您需要将引用添加到 系统。目录服务。帐户管理才能正常工作。这只是为了获得用户角色,但是如果需要,可以扩展到包括其他内容。

using System.DirectoryServices.AccountManagement;


PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "DaomainName");
UserPrincipal u = UserPrincipal.FindByIdentity(ctx, "Username");


List<UserRole> UserRoles = u.GetGroups().Select(x => new UserRole { Role = x.Name }).ToList();


public partial class UserRole
{
public string Role { get; set; }
}