使用 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
中的所有值,并且我有一个值为 1 的“子”声明。
为什么 ClaimTypes.NameIdentifier 没有映射到“sub”?
为了不让 Microsoft Identity 覆盖声明名称,您必须在 API 启动中的
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
之前使用 app.UseAuthentication()
。使用直接“sub”声明而不是 ClaimThypes.NameIdentifier,例如
var id = this.User.FindFirstValue("sub");
如需进一步参考,请参阅详细讨论: https://github.com/IdentityServer/IdentityServer4/issues/2968#issuecomment-510996164
我假设在 OIDC 配置中,您已使用以下命令清除了 Microsoft JWT 令牌处理程序上的入站声明类型映射:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
然后您可以手动设置声明的声明类型映射
sub
:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
静态字符串
ClaimTypes.NameIdentifier
具有以下值: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
所以难怪它不能用来查找
sub
索赔的价值。
如果您知道
sub
声明包含用户 ID,则只需使用 sub
字符串即可进行查找。
ClaimTypes.NameIdentifier
仅在使用默认入站声明类型映射创建 ClaimsPrincipal
时才用于查找用户 ID,该映射将 sub
声明映射到 http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
。
但即使在这种情况下,使用
userManager.Options.ClaimsIdentity.UserIdClaimType
也更合适,因为这是原始映射中使用的实际值(默认为 ClaimTypes.NameIdentifier
,但可以自定义)。
(但是,是的,这整个映射非常混乱,并且存在许多 Github 问题,甚至 MS 开发人员也感叹这是仅仅由于遗留原因而存在的邪恶。)
Nan Yu 的答案不再有效,可能是由于此重大更改的结果。我认为从那时起,惯用的方法就是在调用
JwtBearerOptions.MapInboundClaims
时将 false
设置为 AuthenticationBuilder.AddJwtBearer
。
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(jwtBearerOptions =>
{
jwtBearerOptions.MapInboundClaims = false;
});