索赔识别性用户ID包含用户名,另一种方式包含

发布于 2025-02-11 00:56:13 字数 1592 浏览 1 评论 0原文

当使用JWT Bearer身份验证中使用ASP.NET Core 5.0中的身份时(不知道后者是否在此播放)时,我有问题,我无法通过使用usermanager.getuserasync(context context> usermanager.getUserAsync(context)。用户)。那是因为在使用它时,我会得到异常说[...]对于INT32不是有效的值。 (参数:'value')Identityuser< t>的通用性是int在我的情况下)。查看usermanager< t>可以看到上述方法使用getUserid,并且本身尝试通过使用findfirstvalue(options.claimsidentity.useridclaimtype)来获取ID )在给定索赔上上。

问题(正如我可以通过自己查看索赔所看到的),以userIdclaimType的索赔包含Identityuser< t> .username and code> and 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();

When using Identity in ASP.NET Core 5.0 with JWT bearer authentication (don't know if the latter is playing into this) I have the problem, that I can't get the user by using userManager.GetUserAsync(Context.User). That is because when using it I get the exception stating [...] is not valid value for Int32. (Parameter: 'value') (the generic of IdentityUser<T> is int in my case). Looking a bit into UserManager<T> one can see that said method uses GetUserId and that itself tries to get the ID by using FindFirstValue(Options.ClaimsIdentity.UserIdClaimType) on the given ClaimsPrincipal.

The problem is (as I can see by looking in to the Claims myself) that the Claim with the name of UserIdClaimType contains the IdentityUser<T>.UserName and UserNameClaimType contains the IdentityUser<T>.Id, so it's exactly the wrong way around.

Am I missing to configure something or is this a bug in ASP.NET Core/Identity 5.0?

In case that it's relevant, this is the code in the ConfigureServices regarding Identity and Authentication:

services.AddDbContext<MyUserContext>((services, options) =>
{
    string usersFilePath = [...];
    options.UseSqlite(
quot;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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼趣 2025-02-18 00:56:13

好的,我找到了引起问题的原因:

登录到我的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或Microsofts Schemas中注册的索赔。 The mapping can be found 在这里

正如人们可以看到的那样> sipertypes.name。因此,如果我想在不进行任何其他配置的情况下开箱即用,我要做的就是索赔,如下所示:

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

Okay, I found what was causing the problem:

On logging in to my web service I create a JWT security token that the user can use on subsequent calls. The code for this is as follows:

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);

The cause for the described problem are the first two claims and how the JwtSecurityTokenHandler processes them. As I use the default JwtSecurityTokenHandler its property MapInboundClaims is set to true. So on requests done with the resulting JWT some JWT claims will automatically get mapped to claims registered in the XML SOAP or Microsofts schemas. The mapping can be found here.

As one can see there JwtRegisteredClaimNames.Sub and JwtRegisteredClaimNames.NameId will get mapped to ClaimTypes.NameIdentifier and JwtRegisteredClaimNames.UniqueName to ClaimTypes.Name. So if I want to get this to work out of the box, without doing any additional configurations, all I have to do is the claims as follows instead:

new Claim[]
{
    new(JwtRegisteredClaimNames.Sub, user.Id.ToString()), // Id now here
    new(JwtRegisteredClaimNames.UniqueName, user.UserName), // UserName now here
    // [...]
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文