User.Identity.IsAuthenticated 当用户 ID 类型从字符串更改为整数时,在 .net Core 中始终为 false

User.Identity.IsAuthenticated always false in .net core when user id type changed from string to integer

我有一个 asp.net 核心应用程序使用 json 网络令牌进行身份验证,当我的用户 ID 是一个字符串时它工作正常,但在更改为 int 后停止工作。

我的 IdentityUser 类型原来是这样的

public class AppUser : IdentityUser
{
     //other properties...
}

我更新了这个;

public class AppUser : IdentityUser<int>
{
     //other properties...
}

我从这里更改了我的启动配置;

        services.Configure<JwtIssuerOptions>(options =>
        {
            options.Issuer = jwtIssuerOptions.Issuer;
            options.Audience = jwtIssuerOptions.Audience;
            options.SigningCredentials = jwtIssuerOptions.SigningCredentials;
        });


        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = jwtIssuerOptions.Issuer,

            ValidateAudience = true,
            ValidAudience = jwtIssuerOptions.Audience,

            ValidateIssuerSigningKey = true,
            IssuerSigningKey = _signingKey,

            RequireExpirationTime = false,
            ValidateLifetime = true,
            ClockSkew = TimeSpan.Zero
        };

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(configureOptions =>
        {
            configureOptions.ClaimsIssuer = jwtIssuerOptions.Issuer;
            configureOptions.TokenValidationParameters = tokenValidationParameters;
            configureOptions.SaveToken = true;
        });

        // add identity
        var builder = services.AddIdentityCore<AppUser>(o =>
        {
            // configure identity options
            o.Password.RequireDigit = false;
            o.Password.RequireLowercase = false;
            o.Password.RequireUppercase = false;
            o.Password.RequireNonAlphanumeric = false;
            o.Password.RequiredLength = 6;
            o.SignIn.RequireConfirmedEmail = true;
        });
        builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
        builder.AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();

对此;

    services.Configure<JwtIssuerOptions>(options =>
        {
            options.Issuer = jwtIssuerOptions.Issuer;
            options.Audience = jwtIssuerOptions.Audience;
            options.SigningCredentials = jwtIssuerOptions.SigningCredentials;
        });


        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = jwtIssuerOptions.Issuer,

            ValidateAudience = true,
            ValidAudience = jwtIssuerOptions.Audience,

            ValidateIssuerSigningKey = true,
            IssuerSigningKey = _signingKey,

            RequireExpirationTime = false,
            ValidateLifetime = true,
            ClockSkew = TimeSpan.Zero
        };

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(configureOptions =>
        {
            configureOptions.ClaimsIssuer = jwtIssuerOptions.Issuer;
            configureOptions.TokenValidationParameters = tokenValidationParameters;
            configureOptions.SaveToken = true;
        });

        // add identity
        var builder = services.AddIdentity<AppUser, IdentityRole<int>>(o =>
        {
            // configure identity options
            o.Password.RequireDigit = false;
            o.Password.RequireLowercase = false;
            o.Password.RequireUppercase = false;
            o.Password.RequireNonAlphanumeric = false;
            o.Password.RequiredLength = 6;
            o.SignIn.RequireConfirmedEmail = true;
        });
        builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole<int>), builder.Services);
        builder.AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();

我使用以下方法生成令牌,这在实现之间是不变的。

    public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
    {
        var claims = new[]
     {
             new Claim(JwtRegisteredClaimNames.Sub, userName),
             new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
             new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
             identity.FindFirst(JwtClaimIdentifiers.Rol),
             identity.FindFirst(JwtClaimIdentifiers.Id)
         };

        // Create the JWT security token and encode it.
        var jwt = new JwtSecurityToken(
            issuer: _jwtOptions.Issuer,
            audience: _jwtOptions.Audience,
            claims: claims,
            notBefore: _jwtOptions.NotBefore,
            expires: _jwtOptions.Expiration,
            signingCredentials: _jwtOptions.SigningCredentials);

        var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

        return encodedJwt;
    }

最后使用此方法创建声明身份;

    public ClaimsIdentity GenerateClaimsIdentity(string userName, int id)
    {
        return new ClaimsIdentity(new GenericIdentity(userName, "Token"), new[]
        {
            new Claim(JwtClaimIdentifiers.Id, id.ToString(), ClaimValueTypes.Integer32),
        });
    }

User.Identity.IsAuthenticated 现在在验证时始终为假,ClaimsIdentity 似乎没有我在将我的 AppUser 从字符串 ID 类型转换为 int Id 类型之前看到的信息。

我目前的最佳理论是问题可能与令牌值的 serialisation/deserialisation 有关,但我正在抓紧救命稻草,不知道如何调试它。

我错过了什么?

你的代码中没有任何东西对我怒目而视(看起来主要区别是你从 AddIdentity 换成了 AddIdentityCore?),但我发现 JWT 身份验证问题,它确实有助于 运行 处于调试模式的应用程序并为 JwtBearerEvents 添加处理程序。
将此添加到您的 Startup .AddJwtBearer 调用中:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddJwtBearer(options =>
    {
      // ... 

      // Add this at the end:
      options.Events = new JwtBearerEvents
      {
        OnAuthenticationFailed = context =>
        {
// Put a breakpoint here
          System.Console.WriteLine(context.Exception);
          return Task.CompletedTask;
        },
      };
    })

如果您 运行 在调试中,将能够检查 context.Exception:

这应该可以更好地解释 JWT 身份验证失败的原因。

参加 我为所有 JwtBearerOptions 活动提供了代表。 None个where命中,说明我的设置不充分,根本没有使用我配置的认证方案。

我恢复到addIdentityCore

var builder = services.AddIdentityCore<AppUser>(o =>

虽然我不能再指定我使用的是 IdentityRole<int> 而不是像这样的默认设置;

var builder = services.AddIdentity<AppUser, IdentityRole<int>>(o =>

如果我有以下行,这似乎是不必要的;

builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole<int>), builder.Services);

通过这些更改,身份验证工作正常,我在 Connor Low 的建议中添加的断点被击中。