【问题标题】:JWT Authentication - UserManager.GetUserAsync returns nullJWT 身份验证 - UserManager.GetUserAsync 返回 null
【发布时间】:2018-12-09 17:20:30
【问题描述】:

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)

usernull

也许,我忘了添加一些额外的声明?

或者,也许,一旦我使用 JWT - 我应该覆盖默认的 UserManager 功能,以便它通过包含 UserIDclaim 获取用户?

或者也许有更好的方法?


附加信息:

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);

【问题讨论】:

  • 您能分享一下您是如何注册身份的吗?
  • 嗨@AlexRiabov,刚刚回答了你的问题,Additional Info 部分下的代码。

标签: c# asp.net-core asp.net-identity claims-based-identity


【解决方案1】:

UserManager.GetUserAsync 内部使用UserManager.GetUserId 检索用户的用户 ID,然后用于从用户存储(即您的数据库)中查询对象。

GetUserId 基本上是这样的:

public string GetUserId(ClaimsPrincipal principal)
{
    return principal.FindFirstValue(Options.ClaimsIdentity.UserIdClaimType);
}

所以这将返回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";
});

【讨论】:

  • 或者...,如果userId 不可用,则可以使用userManager.FindByNameAsync(username) 代替,如果这符合业务需求。
  • 简单地做new Claim(ClaimTypes.NameIdentifier, user.Id) 为我工作。以前是user.UserName。没有意识到“名称标识符”将是一个 ID。谁会砰的一声。
  • @mwilson 您如何使用声明主要取决于您的应用程序。有不同的方法来解决这个问题,这也取决于你的 id 是什么。
  • 很好的解决方案。就我而言,Startup.ConfigureServices 解决方案对我有用。在控制器中设置断点并浏览用户->声明帮助我了解我的组织使用哪种声明类型来获取用户 ID。然后设置 options.ClaimsIdentity.UserIdClaimType = ClaimTypes.[option] 为我做了。
  • UserManager.GetUserAsync 最终调用IUserStore 实现的方法FindByIdAsync,这有助于了解您是否需要调试自定义IUserStore 实现。
【解决方案2】:

当您创建声明时,您只需执行以下操作:

 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)
 };

【讨论】:

    猜你喜欢
    • 2017-06-12
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    • 1970-01-01
    • 2021-03-18
    • 2018-10-30
    • 2020-05-11
    相关资源
    最近更新 更多