即使声明中有角色,IsInRole仍返回false

13

我正在进行基于声明的身份验证,并且已经正常工作。现在我想添加角色授权。 我有用户角色声明(例如 "Admin")

当调用IsInRole()方法时,会检查当前用户是否拥有该角色。 在支持声明的应用程序中,角色由角色声明类型表示,应在令牌中可用。 角色声明类型使用以下URI表示:http://schemas.microsoft.com/ws/2008/06/identity/claims/role
//Include all claims
//claims is List<Claim> with all claims
 var id = new ClaimsIdentity(claims, "Cookies");
 Request.GetOwinContext().Authentication.SignIn(id);

如果我检查用户是否在角色中,将会得到false。虽然我拥有值为"Admin"的角色声明。

User.IsInRole("Admin");

还有,在我的API上授权属性将不起作用。

[Authorize (Roles = "Admin")]

我可能误解了如何使角色对用户可见的逻辑。仅在索赔清单中拥有角色可能是不够的?

5个回答

22
如果您的服务使用Windows身份验证,则您收到的IPrincipal.Identity将是WindowsPrincipal类型。这有点误导人,但WindowsPrincipal.IsInRole()查找的ClaimType并不是您可以合理地期望的ClaimTypes.Role,而是ClaimTypes.GroupSid
然而,您不应该假定当前身份使用的实际ClaimType来指定角色,因为不同类型的标识使用不同的值。而是应该引用ClaimsIdentity.RoleClaimType属性。
我们已经按照以下方式实现了一个IAuthenticationFilter:
public Task AuthenticateAsync(HttpAuthenticationContext context, cancellationToken)
{
    var principal = context.Principal;

    if(principal.Identity is ClaimsIdentity && principal.Identity.IsAuthenticated)
    {
        var ci = (ClaimsIdentity)principal.Identity;
        // get the user's additional roles from somewhere and add Claims
        ci.AddClaim(new Claim(ci.RoleClaimType, "MyRole"));
    }
}

这使得我们可以在ASP.Net控制器中使用标准的AuthorizeAttribute机制。例如:

[Authorize(Roles="MyRole")]
public IHttpActionResult Get()
{
    //authenticated and authorised code here
}

请参阅MSDN上的ClaimsIdentity.RoleClaimType以获得更多澄清。

请注意:WindowsPrincipal添加用户定义的角色可能会导致问题。 .Net Framework 4.5当前实现(截至2017年4月)在检查角色时有时会抛出异常,希望从Active Directory中获取角色的详细信息。有关替代方法,请参见此问题


4

可能,这个声明的ClaimType只是"role"。

您应该使用Microsoft Schema创建声明:

manager.AddClaim(dn1.Id, claim: new Claim(ClaimTypes.Role.ToString(), "ADMINISTRATOR"));

那么User.IsInRole("Admin");[Authorize(Roles="Admin")]将正常工作。

这是因为Microsoft Identity使用架构:

http://schemas.microsoft.com/ws/2008/06/identity/claims/role

用于角色检查。 我建议您检查ASPNETIdentity数据库,以完整了解如何插入声明的方式。 我非常确定AspNetUserClaims的ClaimType不像Microsoft Schema。

问候


用户Id是@PhilipStratford。 - DarioN1
非常感谢 @DarioN1,我愿意相信这确实是正确的答案。 - Donald N. Mafa
实际上,我需要这个:identity.AddClaim(new Claim(Microsoft.IdentityModel.Claims.ClaimTypes.Role, userRole)); - Donald N. Mafa

2

简短摘要 区分大小写,也许?

我发现默认情况下使用的检查方式...

  [Authorize(Roles = "RoleA,RoleB")] 

...是区分大小写的。

我创建了大小写混合的角色,并使用AspNetCore的Identity管理器进行测试,使用非EF内存实现。
UserManager.IsInRole("RoleA") 返回true,但通过ClaimsPrincipal和HttpContext.User.IsInRole("RoleA") 检查时返回false。我将声明转储到文本中,发现正确的MS架构有角色声明...

    ClaimType:[http://schemas.microsoft.com/ws/2008/06/identity/claims/role], ClaimValue:[ROLEA], Issuer:[TokenServer]
    ClaimType:[http://schemas.microsoft.com/ws/2008/06/identity/claims/role], ClaimValue:[ROLEB], Issuer:[TokenServer]

...但是声明值(角色)是大写的。
要解决这个问题,我只需要将属性更改为...

[Authorize(Roles = "ROLEA,ROLEB")]

...然后它就起作用了。

因此,如果您在AspNetCore中遇到了获取角色授权的问题,请尝试阅读声明,并确切地匹配声明。您可以通过访问HttpContext.User.Claims对象来读取声明...

        foreach (var claim in HttpContext.User.Claims)            
            Console.WriteLine($"ClaimType:[{claim.Type}], ClaimValue:[{claim.Value}], Issuer:[{claim.Issuer}]");

当然,我可能会把角色编码成大写字母,或者在某个地方使用了“NormalisedRole”,但你也可能犯同样的错误...


2
请注意,HttpContext.User.Identity.RoleClaimType: "role" 可能与 ClaimTypes.Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" 不同。因此,在生成声明标识时,您可能需要使用 "role" 作为键添加声明,而不是使用 ClaimTypes 常量。ClaimsIdentity.IsInRole(String) 使用由 ClaimsIdentity.RoleClaimType 定义的声明键。我的工厂代码如下...
            var identity = await base.GenerateClaimsAsync(user);
            var roles = await UserManager.GetRolesAsync(user);
            foreach (var role in roles)
            {
                identity.AddClaim(new Claim(ClaimTypes.Role, role));
                identity.AddClaim(new Claim("role", role));
            }

            return identity;

第一个添加其实是多余的,但让我感觉我正在添加正确的索赔。

我正在使用Identityserver和.NET Core。在我的情况下,使用字符串“Role”而不是ClaimTypes.Role有效。+1 - MIKE

0

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