我已经成功地在我的 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 添加到字典时,它添加了一个重复的键。
我一定误解了这个实现是如何工作的,任何帮助将不胜感激。
答案 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 声明似乎是合法的。 [编辑:我测试了添加多个角色声明并针对它们进行授权,它对我有用。]