ClaimsIdentity UserId包含UserName,反之亦然



在ASP中使用Identity时。. NET Core 5.0与JWT承载身份验证(不知道后者是否在发挥这一点)我有问题,我不能通过使用userManager.GetUserAsync(Context.User)获得用户。这是因为当使用它时,我得到了异常,说明[...] is not valid value for Int32. (Parameter: 'value')(在我的情况下,IdentityUser<T>的通用是int)。查看一下UserManager<T>,可以看到上面所说的方法使用GetUserId,并且它本身试图通过在给定的ClaimsPrincipal上使用FindFirstValue(Options.ClaimsIdentity.UserIdClaimType)来获取ID。

问题是(正如我自己通过查看索赔所看到的),名称为UserIdClaimType的索赔包含IdentityUser<T>.UserName,UserNameClaimType包含IdentityUser<T>.Id,所以这完全是错误的方式。

我错过了配置的东西或这是一个错误在ASP。. NET Core/Identity 5.0?

,它是相关的,这是ConfigureServices有关标识和身份验证的代码:

services.AddDbContext<MyUserContext>((services, options) =>
{
string usersFilePath = [...];
options.UseSqlite($"Filename={usersFilePath}");
});
services.AddIdentityCore<IdentityUser<int>>()
.AddEntityFrameworkStores<MyUserContext>();
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new()
{
// [...]
};
})
.AddApplicationCookie();

好了,我找到了导致问题的原因:

在登录到我的web服务时,我创建了一个JWT安全令牌,用户可以在随后的调用中使用。代码如下:

var parameters = options.TokenValidationParameters;
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = parameters.ValidIssuer,
Subject = new ClaimsIdentity(new Claim[]
{
new(JwtRegisteredClaimNames.Sub, user.UserName),
new(JwtRegisteredClaimNames.UniqueName, user.Id.ToString()),
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), // will ensure JWT token is unique every time
}),
Audience = parameters.ValidAudience,
Expires = DateTime.UtcNow.AddSeconds(ExpirationSeconds),
NotBefore = DateTime.UtcNow,
//IssuedAt = DateTime.UtcNow, // not necessary, will be set automatically
SigningCredentials = parameters.GetSigningCredentials(),
};
var tokenHandler = options.GetJwtSecurityTokenHandler();
var jwtToken = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
string accessToken = tokenHandler.WriteToken(jwtToken);

问题描述的原因是前两个索赔和JwtSecurityTokenHandler如何处理它们。因为我使用默认的JwtSecurityTokenHandler,它的属性MapInboundClaims被设置为true。因此,对于使用结果JWT完成的请求,一些JWT声明将自动映射到XML SOAP或microsoft模式中注册的声明。可以在这里找到映射。

可以看到,JwtRegisteredClaimNames.SubJwtRegisteredClaimNames.NameId将映射到ClaimTypes.NameIdentifier,JwtRegisteredClaimNames.UniqueName将映射到ClaimTypes.Name。因此,如果我想让它开箱即用,而不做任何额外的配置,我所要做的就是像下面这样声明:

new Claim[]
{
new(JwtRegisteredClaimNames.Sub, user.Id.ToString()), // Id now here
new(JwtRegisteredClaimNames.UniqueName, user.UserName), // UserName now here
// [...]
}

最新更新