繁体   English   中英

当用户 ID 类型从字符串更改为 integer 时,User.Identity.IsAuthenticated 在 .net 核心中始终为假

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

我有一个 asp.net 核心应用程序,它使用 json web 令牌进行身份验证,当我的用户 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 类型之前看到的信息。

到目前为止,我所拥有的最好的理论是,问题可能与令牌值的序列化/反序列化有关,但我正抓着稻草,几乎不知道如何调试它。

我错过了什么?

在你的代码中没有什么让我看的东西(看起来主要的区别是你从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 身份验证失败。

接受Connor Low 的建议,我为所有JwtBearerOptions事件提供了代表。 这些都没有命中,表明我的设置不足,并且我配置的身份验证方案根本没有被使用。

我恢复到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 的建议中添加的断点被击中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM