簡體   English   中英

JWT 身份驗證 - UserManager.GetUserAsync 返回 null

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

usernull

也許,我忘了添加一些額外的聲明?

或者,一旦我使用 JWT - 我應該覆蓋默認的UserManager功能,以便它通過持有UserIDclaim獲取用戶?

或者也許有更好的方法?


附加信息:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM