[英]JWT Authentication - UserManager.GetUserAsync returns null
在AuthController
进行身份验证时,我创建了一些声明- UserID
就是其中之一。
...
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim("UserID", user.Id.ToString()),
})
当 Angular 应用发出请求时,我能够在另一个 controller 中获取UserID
Claim claimUserId = User.Claims.SingleOrDefault(c => c.Type == "UserID");
ControllerBase.User
实例包含.Identity
object,后者又包含Claims
集合。
Identity.IsAuthenticated
等于True
。
Identity.Name
包含admin
字符串(相关用户的名称)。
如果我尝试像这样获取用户:
var user = await UserManager.GetUserAsync(HttpContext.User)
user
是null
。
也许,我忘了添加一些额外的声明?
或者,一旦我使用 JWT - 我应该覆盖默认的UserManager
功能,以便它通过持有UserID
的claim
获取用户?
或者也许有更好的方法?
附加信息:
Identity
注册如下
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
ApplicationUser.Id
字段是bigint
(或 C# 的long
)类型
此外,我使用 UserManager 在EF Seed Data
中创建用户,该用户使用ServiceProvider
解析
_userManager = scope.ServiceProvider.GetService<UserManager<ApplicationUser>>();
...
adminUser.PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(adminUser, "123qwe");
_userManager.CreateAsync(adminUser);
UserManager.GetUserAsync
内部使用UserManager.GetUserId
来检索用户的用户 ID,然后该用户 ID 用于从用户存储(即您的数据库)查询对象。
GetUserId
基本上如下所示:
public string GetUserId(ClaimsPrincipal principal)
{
return principal.FindFirstValue(Options.ClaimsIdentity.UserIdClaimType);
}
所以这将返回Options.ClaimsIdentity.UserIdClaimType
的声明值。 Options
是您用来配置 Identity 的IdentityOptions
对象。 默认情况下, UserIdClaimType
值为ClaimTypes.NameIdentifier
,即"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
。
因此,当您尝试使用UserManager.GetUserAsync(HttpContext.User)
,该用户主体具有UserID
声明,用户管理器只是在寻找不同的声明。
您可以通过切换到ClaimTypes.NameIdentifier
来解决此ClaimTypes.NameIdentifier
:
new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
})
或者您正确配置 Identity,以便它使用您的UserID
声明类型:
// in Startup.ConfigureServices
services.AddIdentity(options => {
options.ClaimsIdentity.UserIdClaimType = "UserID";
});
当你创建Claims 时,你只需要像我一样做
List<Claim> claims = new()
{
new Claim(ClaimTypes.NameIdentifier, user.Id), // this line is important
new Claim(ClaimTypes.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, jti)
};
对我来说,这是一个给出错误建议的教程,它为 JWT 令牌的“子”声明分配了“一般描述”。
ClaimTypes.NameIdentifier
的声明条目是从 JWT 授权库中的“子”声明自动创建的,因此它最终是双重的。 一个值不正确,一个值正确。
这是不正确的实现:
private Claim[] CreateClaims(IdentityUser user)
{
return new[] {
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Sub, _configuration["Jwt:Subject"]),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),
};
}
这是正确的实现:
private Claim[] CreateClaims(IdentityUser user)
{
return new[] {
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),
};
}
正确实施后声明的外观:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.