User.IsInRole 始终 returns false 使用令牌身份验证

User.IsInRole always returns false with Token Authentication

我 ASP.NET Core 2 配置为使用 JWT 令牌进行身份验证。配置如下所示:

services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;

    })
    .AddJwtBearer(options =>
    {
        options.RequireHttpsMetadata = false;
        options.SaveToken = true;

        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidIssuer = Configuration["Tokens:Issuer"],
            ValidAudience = Configuration["Tokens:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
        };
    });

然后我创建了一个用户登录的方法,如下所示:

[AllowAnonymous]
[HttpPost]
[Route("token")]
public async Task<IActionResult> Token([FromBody] LoginViewModel model)
{
    if (!ModelState.IsValid) return BadRequest("Could not create token");

    var user = await _userManager.FindByNameAsync(model.UserName);

    if (user == null) return BadRequest("Could not create token");
    var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, false);
    if (!result.Succeeded) return BadRequest("Could not create token");
    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, user.Email),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
    };

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Tokens:Key"]));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

    var roles = await _userManager.GetRolesAsync(user);

    var token = new JwtSecurityToken(_configuration["Tokens:Issuer"],
        _configuration["Tokens:Issuer"],
        claims,
        expires: DateTime.Now.AddMinutes(30),
        signingCredentials: creds);

    return Ok(new {
        access_token = new JwtSecurityTokenHandler().WriteToken(token),
        roles });
}

}

我保存令牌并在我的请求中使用它。我有一个非常简单的 api 端点:

[HttpGet("users")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult GetUsers()
{
    var isInRole = HttpContext.User.IsInRole(Roles.Administrator);
    return Ok(_service.GetAllUsers());
}

这里我是在方法里面获取的,但是isInRole一直是false。尽管我的 var roles = await _userManager.GetRolesAsync(user); returns 角色列表包括管理员。为什么这不起作用?

您需要像这样将 Role 声明添加到您的 claims 数组中

var claims = new[]
{
    new Claim(JwtRegisteredClaimNames.Sub, user.Email),
    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
    //role claim
    new Claim(ClaimTypes.Role, "Administrator")
};

这是 Asp.Net 将在 [Authorize(Roles="Administrator")] 属性和 HttpContext.User.IsInRole("Administrator");

中查看的内容

同样地,ClaimTypes.Name 用于在您的控制器中生成 User.Identity.Name

我建议您阅读 Rui Figueiredo Secure a Web Api in ASP.NET Core 关于该主题的精彩文章

public async Task<string> GenerateEncodedToken(string userName, string email, List<string> roles, ClaimsIdentity identity)
        {
            var claims = new List<Claim>
            {
                new Claim(JwtRegisteredClaimNames.Sub, userName),
                new Claim(JwtRegisteredClaimNames.UniqueName, userName),
                new Claim(JwtRegisteredClaimNames.Email, email),
                new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
                new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64)
            };

            var id = identity.FindFirst(Constants.Strings.JwtClaimIdentifiers.Id);
            claims.Add(id);

            roles.ForEach(role =>
            {
                claims.Add(new Claim(ClaimTypes.Role, role));
            });


            var jwt = new JwtSecurityToken(
                issuer: _jwtOptions.Issuer,
                audience: _jwtOptions.Audience,
                claims: claims,
                notBefore: _jwtOptions.NotBefore,
                expires: _jwtOptions.Expiration,
                signingCredentials: _jwtOptions.SigningCredentials);

            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

            return encodedJwt;
        }