JWT 身份验证 - UserManager.GetUserAsync returns 空
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 应用发出请求时,我可以在另一个控制器中获取 UserID
Claim claimUserId = User.Claims.SingleOrDefault(c => c.Type == "UserID");
ControllerBase.User
实例包含 .Identity
对象,而对象又包含 Claims
集合。
Identity.IsAuthenticated
等于 True
.
Identity.Name
包含 admin
字符串(相关用户的名称)。
如果我尝试这样获取用户:
var user = await UserManager.GetUserAsync(HttpContext.User)
user
是 null
。
也许,我忘了添加一些额外的声明?
或者,一旦我使用 JWT - 我应该覆盖默认的 UserManager
功能,以便它通过 claim
获取用户,其中包含 UserID
?
或者也许有更好的方法?
附加信息:
Identity
注册如下
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
ApplicationUser.Id
字段是 bigint
(或在 C# 中的 long
)类型
此外,我在 EF Seed Data
中使用 UserManager 创建用户,使用 ServiceProvider
解析
_userManager = scope.ServiceProvider.GetService<UserManager<ApplicationUser>>();
...
adminUser.PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(adminUser, "123qwe");
_userManager.CreateAsync(adminUser);
UserManager.GetUserAsync
internally uses UserManager.GetUserId
检索用户的用户 ID,然后用于从用户存储(即您的数据库)中查询对象。
GetUserId
基本上是这样的:
public string GetUserId(ClaimsPrincipal principal)
{
return principal.FindFirstValue(Options.ClaimsIdentity.UserIdClaimType);
}
所以这个 returns 的声明值 Options.ClaimsIdentity.UserIdClaimType
。 Options
是您用来配置身份的 IdentityOptions
object。默认情况下 UserIdClaimType
的值为 ClaimTypes.NameIdentifier
,即 "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
.
因此,当您尝试使用 UserManager.GetUserAsync(HttpContext.User)
时,该用户主体有一个 UserID
声明,用户管理器只是在寻找一个不同的声明。
您可以通过切换到 ClaimTypes.NameIdentifier
:
来解决这个问题
new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
})
或者您正确配置身份,以便它将使用您的 UserID
声明类型:
// in Startup.ConfigureServices
services.AddIdentity(options => {
options.ClaimsIdentity.UserIdClaimType = "UserID";
});
当您创建声明时,您只需执行以下操作:
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)
};
在 AuthController
进行身份验证时,我创建了一些 声明 - UserID
就是其中之一。
...
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim("UserID", user.Id.ToString()),
})
当 Angular 应用发出请求时,我可以在另一个控制器中获取 UserID
Claim claimUserId = User.Claims.SingleOrDefault(c => c.Type == "UserID");
ControllerBase.User
实例包含 .Identity
对象,而对象又包含 Claims
集合。
Identity.IsAuthenticated
等于True
.Identity.Name
包含admin
字符串(相关用户的名称)。
如果我尝试这样获取用户:
var user = await UserManager.GetUserAsync(HttpContext.User)
user
是 null
。
也许,我忘了添加一些额外的声明?
或者,一旦我使用 JWT - 我应该覆盖默认的 UserManager
功能,以便它通过 claim
获取用户,其中包含 UserID
?
或者也许有更好的方法?
附加信息:
Identity
注册如下
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
ApplicationUser.Id
字段是 bigint
(或在 C# 中的 long
)类型
此外,我在 EF Seed Data
中使用 UserManager 创建用户,使用 ServiceProvider
_userManager = scope.ServiceProvider.GetService<UserManager<ApplicationUser>>();
...
adminUser.PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(adminUser, "123qwe");
_userManager.CreateAsync(adminUser);
UserManager.GetUserAsync
internally uses UserManager.GetUserId
检索用户的用户 ID,然后用于从用户存储(即您的数据库)中查询对象。
GetUserId
基本上是这样的:
public string GetUserId(ClaimsPrincipal principal)
{
return principal.FindFirstValue(Options.ClaimsIdentity.UserIdClaimType);
}
所以这个 returns 的声明值 Options.ClaimsIdentity.UserIdClaimType
。 Options
是您用来配置身份的 IdentityOptions
object。默认情况下 UserIdClaimType
的值为 ClaimTypes.NameIdentifier
,即 "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
.
因此,当您尝试使用 UserManager.GetUserAsync(HttpContext.User)
时,该用户主体有一个 UserID
声明,用户管理器只是在寻找一个不同的声明。
您可以通过切换到 ClaimTypes.NameIdentifier
:
new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
})
或者您正确配置身份,以便它将使用您的 UserID
声明类型:
// in Startup.ConfigureServices
services.AddIdentity(options => {
options.ClaimsIdentity.UserIdClaimType = "UserID";
});
当您创建声明时,您只需执行以下操作:
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)
};