You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 5.0 JWT认证下UserId与UserName声明值颠倒问题

问题原因

这不是ASP.NET Core 5.0 Identity组件的原生bug,是配置不完整+JWT生成逻辑错位导致的:

  1. UserManager.GetUserAsync内部会从传入的ClaimsPrincipal中读取Options.ClaimsIdentity.UserIdClaimType对应的声明值,尝试转换为用户主键类型(int)后查询用户。你当前拿到的声明中用户ID和用户名完全颠倒,本质是生成JWT令牌时给两个声明赋错了值。
  2. 你使用AddIdentityCore注册Identity服务时,没有显式指定声明类型映射规则,且JwtBearer默认开启的入站声明映射可能改变声明类型匹配关系,进一步加剧了声明错位的问题。
  3. 现有Identity配置不完整,仅调用AddEntityFrameworkStores缺少必要的服务注册,后续调用其他Identity接口也可能出现异常。
修复方案

按以下步骤调整即可解决:

  • 修正JWT生成逻辑,确保声明赋值正确
    生成JWT时,必须将用户主键值赋值给UserIdClaimType对应的声明,用户名赋值给UserNameClaimType对应的声明,不要写反。参考正确实现:

    // 假设已经通过用户名密码校验拿到了user对象
    var claims = new List<Claim>
    {
        // 用户主键赋值给NameIdentifier(Identity默认的UserId声明类型)
        new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
        // 用户名赋值给Name(Identity默认的UserName声明类型)
        new Claim(ClaimTypes.Name, user.UserName),
        // 其余角色、自定义业务声明按需添加
    };
    
    var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(你的JWT密钥));
    var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
    var securityToken = new JwtSecurityToken(
        issuer: 你的JWT签发方,
        audience: 你的JWT受众,
        claims: claims,
        expires: DateTime.Now.AddHours(过期时长),
        signingCredentials: credentials
    );
    var token = new JwtSecurityTokenHandler().WriteToken(securityToken);
    

    如果你习惯使用JWT标准短声明(sub存用户ID、name存用户名),后续Identity配置要对应调整声明类型,保持两边完全一致即可。

  • 补全Identity配置,显式指定声明映射规则
    修改ConfigureServices中的Identity注册代码,显式声明使用的声明类型,补全必要服务:

    services.AddIdentityCore<IdentityUser<int>>(options =>
    {
        // 显式指定用户ID、用户名对应的声明类型,和JWT生成逻辑保持一致
        // 如果用JWT标准短声明,这里就写 options.ClaimsIdentity.UserIdClaimType = "sub";
        options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier;
        options.ClaimsIdentity.UserNameClaimType = ClaimTypes.Name;
        // 密码规则、登录校验等其余配置按需设置
    })
    .AddEntityFrameworkStores<MyUserContext>()
    .AddDefaultTokenProviders(); // 补全默认令牌服务,避免后续账号相关操作异常
    
  • 关闭JwtBearer的默认入站声明映射
    JwtBearer认证默认会将JWT原生短声明映射为WS-*规范的长声明类型,容易出现匹配错位,在JwtBearer配置中关闭该特性:

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            // 关闭默认声明映射,保持JWT内声明和写入时完全一致
            options.MapInboundClaims = false;
            options.TokenValidationParameters = new TokenValidationParameters
            {
                // 保留你原有的令牌验证配置:ValidateIssuer、ValidateAudience、IssuerSigningKey等
            };
        })
        .AddApplicationCookie();
    
  • 校验修复结果
    部署后在受保护接口断点查看Context.User.Claims,确认UserIdClaimType对应的值为int格式的用户ID、UserNameClaimType对应的值为用户名,此时调用userManager.GetUserAsync(Context.User)即可正常返回用户对象,不会出现int类型转换异常。


内容的提问来源于stack exchange,提问作者Christoph Mett

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 10:57:18