为什么ClaimTypes.NameIdentifier不能映射到'sub'?

37

我使用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);

}

我得到了所有的claims,但是id为空...

我检查了所有claims的值,发现一个名为'sub'的claim,其值为1。

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


4
尝试设置以下内容:JwtSecurityTokenHandler.DefaultMapInboundClaims = false; 这主要是为了解决“sub”声明被翻译为“nameidentifier”声明的问题。 - PmanAce
它没有解决问题...id仍然为空。 - Miguel Moura
这是一个好问题,所以我点了个赞(从-1到0)。但是你的例子与你的问题无关。如果你在你的声明中看到了“sub”,那么使用“sub”的FindFirstValue。 - Daniel B
4个回答

36

1
这应该被标记为正确答案。 - Philippe
请确保查看来自@Dominion的答案,建议使用较新的JsonWebTokenHandler.DefaultInboundClaimTypeMap.Clear() - undefined

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

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

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
你可以手动设置声明类型映射来设置声明sub的类型:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);

我尝试了你的建议,但仍然是null...不知道发生了什么事... - Miguel Moura
如果您删除了这行代码:JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();,会发生什么? - Nan Yu
使用Clear方法时,我收到了错误信息:'System.ArgumentException' in System.Private.CoreLib.dll: '已添加具有相同键的项。键:sub' - Miguel Moura
1
请尝试删除以下代码行:JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);,并将这两个代码都删除。 - Nan Yu
非常感谢...您的代码在清除默认的传入声明类型映射(DefaultInboundClaimTypeMap.Clear())时添加了NameIdentifier声明类型,解决了其他一些问题。 - Ajt

8

静态字符串ClaimTypes.NameIdentifier的值为:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier

所以不难理解为什么它不能用于查找sub声明的值。

如果您知道sub声明包含用户ID,您可以直接使用sub字符串进行查找。

ClaimTypes.NameIdentifier只适用于查找用户ID的情况,当ClaimsPrincipal使用默认传入的声明类型映射创建时,将sub声明映射到http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier

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

(但是,整个映射过程相当令人困惑,有许多Github问题开放,甚至微软开发人员也对此表示遗憾,因为它仅出于遗留原因而存在。)


6
南宇的答案在.NET 8 Preview 7之后不再适用。我认为自那时以来,惯用的方法是在调用AuthenticationBuilder.AddJwtBearer时将JwtBearerOptions.MapInboundClaims设置为false

            services
                .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(jwtBearerOptions =>
                {
                    jwtBearerOptions.MapInboundClaims = false;
                });

或者,按照旧方法的精神,只需将JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();更改为JsonWebTokenHandler.DefaultInboundClaimTypeMap.Clear(); 请参阅此 GitHub 问题中的讨论。

谢谢!在更新到.NET 8之后,发现非常奇怪的是FindFirstValue对于UserIdClaimType的返回值突然变成了用户名而不是用户ID。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接