ASP.NET Core JWTAuthentication 和 Authorize 角色声明

时间:2021-03-14 21:31:48

标签: c# asp.net-core jwt

我已经成功地在我的 API 上使用了 JWT 令牌身份验证,但是,我正在努力将角色声明集成到身份验证过程中。

我想要实现的是能够将以下内容添加到我的控制器中的调用中,并让站点自动针对经过身份验证的用户检查角色声明:

[Authorize(Roles = "SiteAdmin")]

这是生成 JWT 令牌的代码:

    private string GenerateJwtToken(UserDto user)
    {
        // generate token that is valid for 7 days
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[] { new Claim("userAccountId", user.UserAccountId.ToString()) }),
            Expires = DateTime.UtcNow.AddHours(_appSettings.JwtExpiryHours),
            SigningCredentials =
                new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };

        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }

我已尝试在此处 (https://www.jerriepelser.com/blog/using-roles-with-the-jwt-middleware/) 遵循本指南并将上述函数更改为以下内容:

    private async Task<string> GenerateJwtToken(UserDto user)
    {
        // generate token that is valid for 7 days
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[] { new Claim("userAccountId", user.UserAccountId.ToString()) }),
            Expires = DateTime.UtcNow.AddHours(_appSettings.JwtExpiryHours),
            SigningCredentials =
                new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
            Claims = await FetchClaims(user.UserAccountId)
        };

        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }

    private async Task<Dictionary<string, object>> FetchClaims(int userId)
    {
        var userPermissions = await GetUserPermissionsByUserId(userId);
        var userClaims = new Dictionary<string, object>();

        foreach (var userPermission in userPermissions)
        {
            userClaims.Add("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", userPermission.PermissionName);
        }

        return userClaims;
    }

虽然上述内容在我的脑海中理论上是有道理的,但我不能添加多个 Role 声明,因为在将 userClaim 添加到字典时,它添加了一个重复的键。

我一定误解了这个实现是如何工作的,任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

我也不确定“权限”是怎么回事,但假设您获得了角色......

您可以简单地以这种方式重构它,并将声明列表添加到您传递给 ClaimsIdentity 的集合中:

        private async Task<string> GenerateJwtToken(UserDto user)
        {
            // generate token that is valid for 7 days
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
            var claims = new List<Claim>(await FetchClaims(user.UserAccountId)) {
                new Claim("userAccountId", user.UserAccountId.ToString())
            };
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(claims),
                Expires = DateTime.UtcNow.AddHours(_appSettings.JwtExpiryHours),
                SigningCredentials =
                    new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };

            var token = tokenHandler.CreateToken(tokenDescriptor);
            return tokenHandler.WriteToken(token);
        }

        private async Task<IEnumerable<Claim>> FetchClaims(int userId)
        {
            var userPermissions = await GetUserPermissionsByUserId(userId);

            return userPermissions
                .Select(x => new Claim(ClaimTypes.Role, x.PermissionName));
        }

(如果需要,您也可以使用 JwtSecurityToken 代替 SecurityTokenDescriptor;它直接接受 IEnumerable<Claim>。)

诚然,我已经有一段时间没有使用角色了,所以如果它不起作用,请告诉我。但是从快速的谷歌搜索来看,向令牌添加多个 Role 声明似乎是合法的。 [编辑:我测试了添加多个角色声明并针对它们进行授权,它对我有用。]

相关问题