为什么 ClaimTypes.NameIdentifier 没有映射到“sub”?

Mig*_*ura 15 asp.net-core identityserver4 asp.net-core-2.2

使用 ASP.NET Core 2.2 和 Identity Server 4 我有以下控制器:

[HttpGet("posts"), Authorize]
public async Task<IActionResult> GetPosts() {

  var authenticated = this.User.Identity.IsAuthenticated;

  var claims = this.User.Identities.FirstOrDefault().Claims;

  var id = this.User.FindFirstValue(ClaimTypes.NameIdentifier);

}
Run Code Online (Sandbox Code Playgroud)

我得到了所有claimsid为空...

我检查了所有值,claims我有一个值为 1 的“子”声明。

为什么 ClaimTypes.NameIdentifier 没有映射到“sub”?

Dom*_*ion 15

Nan Yu的答案从 .NET 8 Preview 7 开始不再有效。我认为从那时起,惯用的方法是在调用中设置JwtBearerOptions.MapInboundClaimsto 。falseAuthenticationBuilder.AddJwtBearer


            services
                .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(jwtBearerOptions =>
                {
                    jwtBearerOptions.MapInboundClaims = false;
                });
Run Code Online (Sandbox Code Playgroud)

或者,本着旧方法的精神,只需更改JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();JsonWebTokenHandler.DefaultInboundClaimTypeMap.Clear();

请参阅此 GitHub 问题中的讨论。


Nan*_* Yu 9

我假设在 OIDC 配置中,您已经使用以下命令清除了 Microsoft JWT 令牌处理程序上的入站声明类型映射:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
Run Code Online (Sandbox Code Playgroud)

然后,您可以手动设置 claim 的声明类型映射sub

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
Run Code Online (Sandbox Code Playgroud)


MrV*_*ype 8

静态字符串ClaimTypes.NameIdentifier具有以下值:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier

因此,难怪它不能用于查找索赔的价值sub

如果您知道声明sub包含用户 ID,则只需使用字符串进行查找即可sub

ClaimTypes.NameIdentifierClaimsPrincipal仅当使用默认入站声明类型映射(将sub声明映射到 )创建 时,才适用于查找用户 ID http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier

但即使在这种情况下,使用 也更合适userManager.Options.ClaimsIdentity.UserIdClaimType,因为这是原始映射中使用的实际值(默认为ClaimTypes.NameIdentifier,但可以自定义)。

(但是,是的,这整个映射非常混乱,并且存在许多 Github 问题,甚至 MS 开发人员也感叹这是仅仅由于遗留原因而存在的邪恶。)


Muh*_*mar 8

  1. 为了不让 Microsoft Identity 覆盖您必须在 API 启动JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();之前使用的声明名称app.UseAuthentication()

  2. 使用直接“sub”声明而不是 ClaimThypes.NameIdentifier 例如 var id = this.User.FindFirstValue("sub");

如需进一步参考,请参阅关于它的详细讨论:https : //github.com/IdentityServer/IdentityServer4/issues/2968#issuecomment-510996164