在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.Sub
和JwtRegisteredClaimNames.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
// [...]
}