【问题标题】:IsInRole return false even if there is role in claims即使声明中有角色,IsInRole 也会返回 false
【发布时间】:2016-05-06 23:34:57
【问题描述】:

我正在处理基于声明的身份验证,它运行良好。 现在我想添加角色授权。 我有用户的角色声明(例如“管理员”)

调用 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);

如果我检查用户是否在角色中,我会得到错误的。虽然我有“管理员”值的角色声明

User.IsInRole("Admin");

同时在我的 api 上授权 attrubute 将不起作用

[Authorize (Roles = "Admin")]

我可能对如何使角色对用户可见的逻辑不正确。仅在声明列表中包含角色可能还不够?

【问题讨论】:

    标签: c# asp.net-mvc-5 authorization iis-8.5


    【解决方案1】:

    请注意 HttpContext.User.Identity.RoleClaimType:“角色”

    可能与 ClaimTypes.Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/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 核心。使用字符串“Role”而不是 ClaimTypes.Role 为我工作 +1
    【解决方案2】:

    您没有提及您使用的是哪种身份验证方法,但是如果您使用的是 JWT 身份验证,那么您需要在生成令牌时将角色添加到 ClaimsIdentity 中,详见这篇博文:ASP.NET Core JWT mapping role claims to ClaimsIdentity

    【讨论】:

      【解决方案3】:

      TL;DR 可能区分大小写?

      我发现默认使用的检查在...

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

      ...区分大小写。

      我以混合大小写创建角色,并使用 AspNetCore 的身份管理器和非 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,但您可能也做了同样的事情...

      【讨论】:

        【解决方案4】:

        如果您的服务使用 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 中获得角色的详细信息。有关替代方法,请参阅this question

        【讨论】:

          【解决方案5】:

          很可能,声明的 ClaimType 只是“角色”。

          您应该使用 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 数据库,以全面了解如何插入 che 声明。 我很确定 AspNetUserClaims 的 ClaimType 与 Microsoft Schema 不同。

          问候

          【讨论】:

          • 用户 ID 是 @PhilipStratford
          • 谢谢你一百万@DarioN1,我愿意相信这实际上是正确的答案。
          • 事实上,我需要这个:identity.AddClaim(new Claim(Microsoft.IdentityModel.Claims.ClaimTypes.Role, userRole));
          猜你喜欢
          • 2016-07-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-14
          • 2021-11-30
          • 1970-01-01
          • 2017-10-20
          相关资源
          最近更新 更多