似乎很多人都在关注这个问题,所以我想分享一些我学习的信息,因为我不久前问过这个问题。它使一些事情变得更加清晰(至少对我来说)并且不那么明显(对我来说就像.NET新手一样)。
正如MarcusHöglund在评论中提到的那样:
它应该与“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在其中一条评论中指出了这一点。
所有基于声明的身份验证中间件(如果正确实现)将使用在身份验证期间收到的声明填充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规范,我正在寻找“sub”声明(当前用户)但却无法找到它。就像Honza Kalfus在答案中所做的那样。
为什么?
因为微软“有时”“有点”不同。或者至少他们会做更多(和意外)的事情。例如,原始问题中提到的官方Microsoft JWT Bearer身份验证中间件。 Microsoft决定在其所有官方身份验证中间件中转换声明(声明的名称)(出于兼容性原因,我不知道更详细)。
您将找不到“子”声明(尽管它是OpenID Connect指定的单个声明)。因为它被转换为these fancy ClaimTypes。这并非全是坏事,如果您需要将不同的声明映射到唯一的内部名称,它允许您添加映射。
您要么坚持使用Microsoft命名(并且必须记住,当您添加/使用非Microsoft中间件时)或者您发现如何为Microsoft中间件转换声明映射。
在JwtBearerAuthentication的情况下,它完成(在StartUp的早期或至少在添加中间件之前):
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
如果你想坚持主题声称的微软命名(不要打败我,如果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);
然后可以通过访问实际的令牌(以其所有的神秘形式)作为字符串(或null)
HttpContext.GetTokenAsync("Bearer", "access_token")
这个方法有一个旧版本(这在.NET Core 2.2中适用于我,没有弃用警告)。
如果您需要解析并从此字符串中提取值,可能How to decode JWT token的问题会有所帮助。
好吧,我希望这个总结对你也有帮助。