c# - 当用户 id 类型从字符串更改为整数时,.net 核心中的 User.Identity.IsAuthenticated 始终为 false
问题描述
我有一个使用 json Web 令牌进行身份验证的 asp.net 核心应用程序,当我的用户 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
.
将此添加到您的启动.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 身份验证失败的原因。