我正在编写一个基于MVC(.NET 4.0)的网站,该网站需要我公司LDAP服务器的登录凭据。我的代码需要的是仅允许属于某个组的用户。例如,我可能正在寻找属于“企业IT”小组的用户。我的凭据可能是“系统管理员”组的一部分,该组是“企业IT”的子组。我正在使用表单身份验证。
如何以递归方式检查用户登录时所在的群组?
答案 0 :(得分:6)
对于搜索此类查询的其他人来说,以下是我在应用程序中的操作方式:
密钥是1.2.840.113556.1.4.1941扩展搜索过滤器。由于此特定过滤器仅适用于DN,因此我首先获取要检查的用户的DN,然后查询组以查看此特定用户是否是链中任何组的成员。
internal const string UserNameSearchFilter = "(&(objectCategory=user)(objectClass=user)(|(userPrincipalName={0})(samAccountName={0})))";
internal const string MembershipFilter = "(&(objectCategory=group)(objectClass=group)(cn=MyGroup)(member:1.2.840.113556.1.4.1941:={0}))";
using (var de = new DirectoryEntry(AppSettings.LDAPRootContainer, AppSettings.AdminUser, AppSettings.AdminPassword, AuthenticationTypes.FastBind))
using (var ds = new DirectorySearcher(de) { Filter = string.Format(UserNameSearchFilter, username) })
{
ds.PropertiesToLoad.AddRange(new[] { "distinguishedName" });
var user = ds.FindOne();
if (user != null)
using (var gds = new DirectorySearcher(de) { PropertyNamesOnly = true, Filter = string.Format(MembershipFilter, user.Properties["distinguishedName"][0] as string) })
{
gds.PropertiesToLoad.AddRange(new[] { "objectGuid" });
return gds.FindOne() != null;
}
}
答案 1 :(得分:3)
我发现将GroupPrincipal.GetMembers
与递归标志一起使用是快速有效的。
public bool IsMember(string groupName, string samAccountName)
{
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, samAccountName))
using(GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName))
{
return group.GetMembers(true).OfType<Principal>().Any(u => u.SamAccountName.Equals(user.SamAccountName, StringComparison.InvariantCultureIgnoreCase));
}
}
答案 2 :(得分:1)
如果要检查特定用户的成员身份,请绑定到相关AD对象并检索tokenGroups属性。它包含二进制形式的所有直接和间接组成员资格 - 它是一个字节数组的数组。每个字节数组都可以传递给SecurityIdentifier类的构造函数,然后转换为NTAccount,其中包含以明文形式显示的组的名称。
var sids = new IdentityReferenceCollection();
foreach (byte[] group in tokenGroups)
{
sids.Add(new SecurityIdentifier(group, 0));
}
var accounts = sids.Translate(typeof(NTAccount));
答案 3 :(得分:0)
这是一个完全不同的解决方案。测试并在我的域上工作。一些注意事项:您必须正确使用DirectorySearcher.Filter。为AD层次结构添加多个OU(按相反顺序,自下而上)。还要注意,为了安全起见,我在“using”语句中处理了一些对象,因为它们实现了System.ComponentModel.Component,而System.ComponentModel.Component又实现了IDisposable ......所以,比抱歉更安全。
public bool IsUserMemberOfGroup(string groupName)
{
// CN is your distro group name. OU is the object(s) in your AD hierarchy. DC is for your domain and domain suffix (e.g., yourDomain.local)
string searchFilter = String.Format(@"(&(objectcategory=user)(sAMAccountName=markp)(memberof=CN={0},OU=System Admins,OU=USA,DC=yourDomain,DC=local))", groupName);
SearchResultCollection searchResult;
using (var dirEntry = new DirectoryEntry("LDAP://dc=yourDomain,dc=local"))
{
using (var dirSearch = new DirectorySearcher(dirEntry))
{
dirSearch.SearchScope = SearchScope.Subtree;
dirSearch.Filter = searchFilter;
searchResult = dirSearch.FindAll();
}
}
if (searchResult.Count <= 0 || searchResult == null) {
return false; // not in group
}
else {
return true; // in group
}
}