似乎很多人都在关注这个问题,所以我想分享一些我在不久前提出这个问题后学到的更多信息。
它使一些事情更清楚(至少对我而言)并且不是那么明显(对我作为 .NET 新手而言)。
正如 Marcus Höglund 在 cmets 中提到的:
“web api”应该是一样的。在 ASP.NET Core Mvc 和 Web Api 合并使用相同的控制器。
这绝对是真的,绝对正确。
因为它在 .NET 和 .NET Core 中都是一样的。
比我刚接触 .NET Core 和真正的 .NET 世界还要早。缺少的重要信息是,在 .NET 和 .NET Core 中,所有身份验证都可以通过其 ClaimsIdentity、ClaimsPrinciple 和 Claims.Properties 缩减到 System.Security.Claims 命名空间。因此,它可用于两种 .NET Core 控制器类型(API 和 MVC 或 Razor 或 ...),并可通过 HttpContext.User 访问。
一个重要的旁注,所有的教程都错过了。
因此,如果您开始在 .NET 中使用 JWT 令牌,请不要忘记对 ClaimsIdentity、ClaimsPrinciple 和 Claim.Properties 充满信心。就是这样。现在你知道了。 Heringer 在其中一个 cmets 中指出了这一点。
所有基于声明的身份验证中间件(如果正确实施)将使用身份验证期间收到的声明填充 HttpContext.User。
据我所知,这意味着人们可以放心地信任 HttpContext.User 中的值。 但请稍等了解在选择中间件时要注意什么。有很多不同的身份验证
中间件已经可用(除了.UseJwtAuthentication())。
使用小型自定义扩展方法,您现在可以像这样获取当前用户 ID(更准确的主题声明)
public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value; }
或者你使用Ateik答案中的版本。
但是等等:有一件奇怪的事情
接下来让我感到困惑的是:根据 OpenID Connect 规范,我正在寻找“子”声明(当前用户)但找不到它。就像 Honza Kalfus 在他的回答中无法做到的那样。
为什么?
因为微软“有时”“有点”不同。或者至少他们做了更多(和意想不到的)事情。例如原始问题中提到的官方 Microsoft JWT Bearer 身份验证中间件。
Microsoft 决定在其所有官方身份验证中间件中转换声明(声明的名称)(出于兼容性原因,我不太了解)。
您不会找到“子”声明(尽管它是 OpenID Connect 指定的单一声明)。因为它被转换为these fancy ClaimTypes。这还不错,如果您需要将不同的声明映射到唯一的内部名称,它允许您添加映射。
要么坚持使用 Microsoft 命名(并且在添加/使用非 Microsoft 中间件时必须注意这一点),要么了解如何为 Microsoft 中间件转换声明映射。
在 JwtBearerAuthentication 的情况下,它已完成(在 StartUp 早期或至少在添加中间件之前完成):
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
如果您想坚持使用 Microsoft 命名主题声明(不要打败我,我现在不确定 Name 是否正确映射):
public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase))?.Value; }
请注意,其他答案使用更高级和更方便的FindFirst 方法。虽然我的代码示例显示它没有你可能应该使用的那些。
因此,您的所有声明都存储在 HttpContext.User 中并可供访问(通过一个名称或另一个名称)。
但是我的令牌呢?
我不知道其他中间件,但 JWT 承载身份验证允许为每个请求保存令牌。但这需要激活(在StartUp.ConfigureServices(...)。
services
.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options => options.SaveToken = true);
然后可以通过
访问作为字符串(或空值)的实际令牌(以所有神秘的形式)
HttpContext.GetTokenAsync("Bearer", "access_token")
这个方法有一个旧版本(这在 .NET Core 2.2 中适用于我,没有弃用警告)。
如果您需要从该字符串中解析和提取值,How to decode JWT token 问题可能会有所帮助。
嗯,我希望这个总结也能帮助到你。