Authorize Policy 属性总是返回 403 禁止使用 .net core Identity 和 JwtBearerAuthentication

Posted

技术标签:

【中文标题】Authorize Policy 属性总是返回 403 禁止使用 .net core Identity 和 JwtBearerAuthentication【英文标题】:Authorize Policy attribute always returns 403 forbidden using .net core Identity and JwtBearerAuthentication 【发布时间】:2017-11-17 06:12:26 【问题描述】:

在this guide 之后,我能够使用

进行身份验证
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.AspNetCore.Authentication.JwtBearer

现在我正在尝试使用角色或声明来保护我的 api 端点。我都试过了,结果相同(403)

仅使用 [Authorize] 即可。

我的代码目前看起来像这样:

控制器:

[Authorize(Policy = "RequireUserRole")]
// Also tried [Authorize(Roles="User")]
public string Get()
   
  return "YO";

启动:

services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<ApplicationContext>();
services.Configure<JWTSettings>(Configuration.GetSection("JWTSettings"));
services.AddAuthorization(options =>

        options.AddPolicy("RequireUserRole", policy => policy.RequireRole("User"));
);

...

app.UseIdentity();

var secretKey = Configuration.GetSection("JWTSettings:SecretKey").Value;
var issuer = Configuration.GetSection("JWTSettings:Issuer").Value;
var audience = Configuration.GetSection("JWTSettings:Audience").Value;
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));

app.UseJwtBearerAuthentication(new JwtBearerOptions

        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        TokenValidationParameters = new TokenValidationParameters
        
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,

                // Validate the JWT Issuer (iss) claim
                ValidateIssuer = true,
                ValidIssuer = issuer,

                // Validate the JWT Audience (aud) claim
                ValidateAudience = true,
                ValidAudience = audience,

                ValidateLifetime = true
        
);

app.UseMvcWithDefaultRoute();

当我创建用户时,我将其分配给角色“用户”

await _userManager.AddToRoleAsync(user, "User");

角色关系创建成功,但到达端点时角色验证失败。

任何帮助表示赞赏!

【问题讨论】:

对我来说值得注意的是 .RequrieClaim("role", "admin") 不起作用,.RequireRole("admin") 这样做了,感谢您给了我尝试的想法 我不得不为 Azure 应用程序授权更改角色声明类型:options.TokenValidationParameters.RoleClaimType = "schemas.microsoft.com/ws/2008/06/identity/claims/role"; 【参考方案1】:

答案就在这个mdsn blog post:

基于角色的授权可通过 ASP.NET 开箱即用 身份。只要用于身份验证的不记名令牌包含 角色元素,ASP.NET Core 的 JWT 不记名身份验证中间件 将使用该数据为用户填充角色。

因此,基于角色的授权属性(如 [Authorize(Roles = "Manager,Administrator")] 来限制对管理员和管理员的访问) 可以 被添加到 API 并立即工作。

所以我在我的访问令牌对象中添加了一个名为角色的元素:

private string GetAccessToken(string userRole)

    var payload = new Dictionary<string, object>
    
        ...
         "roles", userRole  
    ;
    return GetToken(payload);

【讨论】:

我认为这在系统中是一种不好的做法,您可能会更改用户角色,并且用户之前登录过一次并且过期时间很长。【参考方案2】:

我阅读了那个 msdn 帖子并在启动时添加了:

   internal class HasRoleRequerementAuthHandler : AuthorizationHandler<HasRoleRequirement>

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasRoleRequirement requirement)
     

        if (context.User.HasClaim(c => c.Type == JwtRegisteredClaimNames.NameId))
            if (context.User.FindFirst(c => c.Type == JwtRegisteredClaimNames.Typ).Value == requirement.RoleName)
                context.Succeed(requirement);
        return Task.CompletedTask;

    
    
internal class HasRoleRequirement : IAuthorizationRequirement

    public readonly string RoleName;

    public HasRoleRequirement(string roleName)
    
        RoleName = roleName;
    

然后添加策略:

       opt.AddPolicy("Test", builder =>
            
                builder.Requirements.Add(new HasRoleRequirement("User"));
            );

我的令牌是这样生成的:

        var claims = new List<Claim>
        
            new Claim(JwtRegisteredClaimNames.NameId, user.Uid),
            new Claim(JwtRegisteredClaimNames.Typ, type.ToString())
        ;


        var creds = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512Signature);

        var tokenDesc = new SecurityTokenDescriptor
        
            Subject = new ClaimsIdentity(claims),
            Expires = DateTime.Now.AddDays(7),
            SigningCredentials = creds
        ;

        var tokenHandler = new JwtSecurityTokenHandler();

        var token = tokenHandler.CreateToken(tokenDesc);
        return tokenHandler.WriteToken(token);

然后我可以使用策略 Auth 标头:

    [HttpGet("TestAuth")]
    [Authorize(Policy = "Test")]
    public IActionResult TestAuth()
    
        return new OkResult();
    

【讨论】:

以上是关于Authorize Policy 属性总是返回 403 禁止使用 .net core Identity 和 JwtBearerAuthentication的主要内容,如果未能解决你的问题,请参考以下文章

Authorize(Roles = "Admin") 总是返回 ACCESS DENIED

Laravel 8 Policy 总是返回“此操作未经授权”。

sec:authorize 总是在浏览器中为百里香视图中的 isAuthenticated() 和 isAnonymous() 返回相同的视图

添加 Authorize 属性时 Web api 核心返回 404

.NET Core Authorize 属性与外部 JWT 身份验证微服务?

向标头添加授权并访问 [Authorize] 控制器