听起来很简单,我发现没有其他问题可以解决我遇到的问题.
第一次尝试:[授权]
经典的方法是简单地在控制器操作上打一个授权数据注释属性并转到城镇:
[Authorize(Roles = @"domain\groupName1")]
没有骰子.我被提示输入凭据.通常这意味着Windows身份验证配置有问题,但设置正常:(1)HttpContext.User是一个WindowsPrincipal对象,(2)我确认另一个已知的组名有效.
第二次尝试:IsInRole()
下一步是采用更老式的路线并使用IPrincipal.IsInRole(),再次,一个返回false,另一个返回true.
var wp = (WindowsPrincipal)User; // false var inGroup1 = wp.IsInRole(@"domain\groupName1"); // true var inGroup2 = wp.IsInRole(@"domain\groupName2");
难倒…所以我打了我的系统书呆子,我们仔细检查一切.用户是群组成员?是.组名拼写正确吗?是.下一步是阻止SID.
第三次尝试:搜索身份的群集
在我的控制器中,我检查WindowsIdentity并查看组集合中有关麻烦组的SID:
var wi = (WindowsIdentity)wp.Identity; var group = wi.Groups.SingleOrDefault(g => g.Value == "group1-sidValue");
组变量是SecurityIdentifier对象.因为它不是null,我们可以确定当前用户是[Authorize()]或IsInRole()尝试无法确认的组的成员.
第四次尝试:DirectoryServices.AccountManagement
在这一点上,我疯了,并添加对AccountManagement API的引用.我通过名称和SID搜索GroupPrincipal的域上下文:
var pc = new PrincipalContext(ContextType.Domain,"domain"); var gp1byName = GroupPrincipal.FindByIdentity(pc,"groupName1") var gp1bySid = GroupPrincipal.FindByIdentity(pc,IdentityType.Sid,"group1-sidValue");
两个组主变量都是成熟的同一个对象,我通过一个监视变量验证了主体的Members集合包含一个与HttpContext上当前WindowsPrincipal具有相同SID的UserPrincipal对象.
题:
我到底在这里错过了什么?当通过对象探索明白且清楚用户是该给定组的有效成员时,为什么两种角色检查方法都会失败?
事实上,一组检查正常,另一组在这一点上似乎不是最奇怪的部分.
解决方法
基本上它是WindowsIdentity和NTAccount(这两者都是System.Security.Principal)之间的翻译问题,最后是实际的Active Directory条目.
在针对AD验证WindowsIdentity时,如果要使用除Sam或Sid之外的任何其他内容,则需要使用System.DirectoryServices.AccountManagement.
警告:在.Net 4.5中,安全主体包括声明,但这不符合上下文.
长说明:
在Windows Authenticated Web应用程序中,HttpContext.User是一个包装底层WindowsIdentity的WindowsPrincipal对象.
对于大多数意图和目的,WindowsIdentity只有两个属性,用于识别经过身份验证的用户:名称和用户.
WindowsIdentity.Name = SamAccountName
WindowsIdentity.User = SID
[Authorize]过滤器属性最终在底层主体上调用IsInRole(字符串角色)…并且IsInRole()字符串重载实例化具有角色的NTAccount(AD条目中的“SamAccountName”).
这解释了上面#1和#2的失败.
要对除了他/她的Sid或SamAccountName之外的任何内容授权HttpContext.User,您将需要DirectoryServices.AccountManagement或经典LDAP.