[英]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.