在ASP.NET Core 10.0中配置JWT Bearer身份验证

在ASP.NET Core 10.0中配置JWT Bearer身份验证

API 通常使用 JWT (JSON Web 令牌) Bearer 身份验证。 虽然其工作方式与Cookie身份验证类似,但身份验证成功时,标识提供者会发出 JWT 或令牌。 可以将这些令牌发送到其他服务器进行身份验证,这与仅发回发证域的 Cookie 不同。 JWT 是一个自包含的令牌,用于封装 API 资源或客户端的信息。 请求JWT的客户端可以使用Authorization请求头和Bearer令牌向API资源请求数据。

JWT 持有者身份验证提供:

  • 身份验证:使用 JwtBearerHandler 时,持有者令牌对于身份验证至关重要。 JwtBearerHandler 验证令牌并从其声明中提取用户的身份信息。
  • 授权: Bearer 令牌通过提供表示用户或应用程序权限的声明集合来启用授权,这非常类似于 cookie.
  • 委托授权:当使用特定于用户的访问令牌而不是应用程序范围的访问令牌在 API 之间进行身份验证时,此过程称为委托授权。

有关持有者身份验证的 JWT 简介,请参阅 JSON Web 令牌。 查看或下载示例代码

本文涵盖以下几个方面:

  • 令牌类型
  • 使用 JWT 令牌保护 API 的安全
  • OIDC/OAuth 如何适应此情况?
  • JWT实现持有者令牌身份验证
  • 创建JWT的推荐方法

令牌类型

有许多类型的令牌和格式。 除测试目的外,请勿自行生成访问令牌或ID令牌。 不遵循已建立标准的自创建令牌:

  • 可能导致安全漏洞。
  • 仅适用于封闭系统。

使用 OpenID Connect 1.0 或 OAuth 标准创建用于 API 访问的访问令牌。

访问令牌

访问令牌:

  • 客户端应用用来向实现 API 的服务器发出请求的字符串。
  • 格式可以不同。 不同的 API 可能会对令牌使用不同的格式。
  • 可以加密。
  • 不应由保存访问令牌的 Web 客户端或 UI 应用读取或解释。
  • 仅用于向 API 提出请求。
  • 通常作为持有者令牌发送到“授权”请求标头中的 API。

请参阅 OAuth 2.0 授权框架 。

应用程序访问令牌和委托访问令牌

访问令牌可以是应用程序访问令牌或委托访问令牌。 这些令牌具有不同的声明,并且以不同的方式进行管理和存储。 应用程序访问令牌通常在应用程序中存储一次,直到过期为止,而委托访问令牌存储在每个用户的 cookie 或安全服务器缓存中。

每当涉及某个用户时,使用委托的用户访问令牌。 下游 API 可以代表经过身份验证的用户请求一个委派用户访问令牌。

发送方约束的访问令牌

访问令牌可以作为持有者令牌 或发送方受限的令牌 来访问资源。 发送方受限令牌要求提出请求的客户端证明拥有私钥才能使用令牌。 证明拥有私钥可确保令牌无法被单独使用。 您可以通过两种方式实现发送方约束令牌:

ID 令牌

ID 令牌是确认用户成功身份验证的安全令牌。 令牌允许客户端验证用户的标识。 JWT 令牌服务器签发包含用户信息声明的 ID 令牌。 ID 令牌始终采用 JWT 格式。

ID 令牌绝不应用于访问 API。

其他令牌

令牌有多种类型,包括 OpenID Connect 和 OAuth 标准规定的访问令牌和 ID 令牌。 刷新令牌可用于刷新 UI 应用,而无需对用户重新进行身份验证。 OAuth JAR 令牌 可以安全地发送授权请求。 可验证凭据流利用 JWT 类型来颁发或验证凭据。 按照规范使用令牌至关重要。 有关详细信息,请参阅本文后面提供的标准链接。

使用 JWT 令牌保护 API

使用 JWT 访问令牌进行 API 授权时,API 会根据提供的令牌授予或拒绝访问。 如果请求未被授权,则返回 401 或 403 响应。 API 不应将用户重定向到标识提供者,以获取新的令牌或请求其他权限。 使用 API 的应用负责获取适当的令牌。 这可确保在 API(授权)与客户端应用程序(身份验证)之间明确实现关注点分离。

注意

HTTP 还允许为未授权返回 404,以免泄露有关资源存在的信息给未经授权的客户端。

401 未授权

401 未授权响应表示所提供的访问令牌不符合规定标准。 这种情况可能是由于多种原因造成的,包括:

  • 签名无效:令牌的签名不匹配,意味着可能存在篡改。
  • 过期:令牌已过期,不再有效。
  • 错误声明:令牌中的关键声明(例如受众(aud)或颁发者(iss))缺失或无效。

注意

从 HTTP 语义 RFC 9110 :生成 401 响应的服务器必须发送标头 WWW-Authenticate 字段(第 11.6.1 节),其中包含至少一个适用于目标资源的质询。

OAuth 规范 提供了有关所需声明及其验证的详细指南。

403 禁止访问

403 禁止 响应通常表示已通过身份验证的用户缺乏访问所请求资源的必要权限。 此条件不同于身份验证问题,例如无效令牌,并且与访问令牌中的标准声明无关。

在 ASP.NET Core 中,可以通过授权来强制执行:

  • 要求和策略 :定义自定义要求,例如“必须是管理员”,并将其与策略相关联。
  • 基于角色的授权 :将用户分配到角色,例如“管理员”或“编辑器”,并根据这些角色限制访问权限。

使用持有者令牌时,OIDC 和/或 OAuth 具有什么作用?

当 API 使用 JWT 访问令牌进行授权时,API 仅验证访问令牌,并且不考虑如何获取令牌。

OpenID Connect (OIDC) 和 OAuth 2.0 为令牌获取提供了标准化的安全框架。 令牌获取方式因应用类型而异。 由于安全令牌获取的复杂性,强烈建议采用这些标准:

  • 对于代表用户和应用程序运行的应用:使用 OIDC 启用委派用户访问。 在 Web 应用中,将机密代码流与 Code Exchange(PKCE)的证明密钥 配合使用以提高安全性。
  • 如果应用没有用户:使用 OAuth 2.0 客户端凭据流获取应用程序访问令牌。

JWT实现持有者令牌身份验证

Microsoft.AspNetCore.Authentication.JwtBearer NuGet 包 可用于验证JWT持有者令牌。

应在 API 中完整验证 JWT持有者令牌。 应验证以下内容:

  • 签名,象征信任与诚信。 这样可以确保令牌是由指定的安全令牌服务创建的,并且没有被篡改。
  • 具有预期值的颁发者声明。
  • 具有预期值的受众声明。
  • 令牌过期。

OAuth 2.0 访问令牌需要以下声明:iss、exp、aud、sub、client_id、iat 和 jti。

如果其中任何声明或值不正确,API 应返回 401 响应。

JWT 持有者令牌基本验证

AddJwtBearer 的基本实现仅能验证受众和颁发者。 签名必须经过验证,以便令牌可以被信任,并且没有被篡改。

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(jwtOptions =>
{
	jwtOptions.Authority = "https://{--your-authority--}";
	jwtOptions.Audience = "https://{--your-audience--}";
});

JWT 持有者令牌的显式验证

该方法 AddJwtBearer 提供多个配置。 某些安全令牌提供程序使用非标准元数据地址,并且可以显式设置参数。 API 可以接受多个颁发者或受众。

无需显式定义参数。 定义取决于访问令牌声明值和用于验证访问令牌的安全令牌服务器。 应尽可能使用默认值。

请参阅映射声明 MapInboundClaims 详细信息。

builder.Services.AddAuthentication()
.AddJwtBearer("some-scheme", jwtOptions =>
{
	jwtOptions.MetadataAddress = builder.Configuration["Api:MetadataAddress"];
	// Optional if the MetadataAddress is specified
	jwtOptions.Authority = builder.Configuration["Api:Authority"];
	jwtOptions.Audience = builder.Configuration["Api:Audience"];
	jwtOptions.TokenValidationParameters = new TokenValidationParameters
	{
		ValidateIssuer = true,
		ValidateAudience = true,
		ValidateIssuerSigningKey = true,
		ValidAudiences = builder.Configuration.GetSection("Api:ValidAudiences").Get<string[]>(),
		ValidIssuers = builder.Configuration.GetSection("Api:ValidIssuers").Get<string[]>()
	};

	jwtOptions.MapInboundClaims = false;
});

具有多个方案的 JWT

API 通常需要支持来自各种颁发者的访问令牌。 可以使用以下方法在 API 中支持多个令牌颁发者:

  • 独立的 API:为每个颁发者创建具有专用身份验证方案的独立 API。
  • AddPolicyScheme :定义多个身份验证方案并实现逻辑,以基于令牌属性(例如颁发者或声明)选择适当的方案。 此方法在单个 API 中提供了更大的灵活性。

要求对所有 API 终结点进行身份验证

使用 SetFallbackPolicy 可在无法根据终结点元数据生成授权策略时,要求由授权中间件处理的请求必须由已通过身份验证的用户发起:

var requireAuthPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();

builder.Services.AddAuthorizationBuilder()
    .SetFallbackPolicy(requireAuthPolicy);

默认策略适用于未指定策略名称的 [Authorize],并要求用户已通过身份验证,除非应用对其进行更改。 有关完整的策略选择规则,请参阅 ASP.NET Core中基于策略的授权 。

还可以使用该 AuthorizeAttribute 属性强制身份验证。 如果使用多个方案,请将 Bearer 方案设为默认身份验证方案,或使用 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme]) 指定它。

控制器中的授权:

[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{

最小 API 中的授权:

app.MapGet("/hello", [Authorize] () => "Hi");

创建JWT的推荐方法

不安全处理访问令牌,例如身份验证不严密或将令牌存储在易受攻击的客户端存储中,可能会导致严重的安全漏洞。 例如,通过本地存储、会话存储或 Web Worker 直接在浏览器中存储访问令牌。 以下部分包含有关使用和创建访问令牌的应用的最佳做法。

使用标准

创建访问令牌时使用 OpenID Connect 或 OAuth 等标准。 请勿在生产应用中创建访问令牌,而无需遵循本文中所述的安全预防措施。 限制创建访问令牌以测试方案。

使用非对称密钥

创建访问令牌时,请务必使用非对称密钥。 公钥可在众所周知的终结点中获得,API 客户端可使用公钥验证访问令牌的签名。

切勿通过用户名/密码请求创建访问令牌

请勿基于用户名/密码请求创建访问令牌。 用户名/密码请求未经身份验证,容易受到模拟和网络钓鱼攻击的攻击。 只能使用 OpenID Connect 流或 OAuth 标准流来创建访问令牌。 偏离这些标准会导致应用不安全。

使用 Cookie

对于安全的 Web 应用,需要一个后端将访问令牌存储在受信任的服务器上。 与客户端浏览器仅共享带有Secure和HttpOnly属性的Cookie。 有关如何在 ASP.NET Core Web 应用中执行此操作,请参阅 OIDC 身份验证文档 。

下游 API

API 偶尔需要代表调用应用中经过身份验证的用户从下游 API 访问用户数据。 虽然实现 OAuth 客户端凭据流是一种选择,但这需要两个 API 应用互相完全信任。 一种更安全的方法是使用零信任策略和授权用户访问令牌。 这种方法:

  • 只为特定用户授予 API 必要的权限,从而提高安全性。
  • 要求 API 为调用应用和 API 的用户创建新的访问令牌。

使用委托用户访问令牌实现零信任策略有几种方法:

使用 OAuth 2.0 令牌交换请求新的委托访问令牌

这是实现这一要求的好方法,但如果必须实现 OAuth 流,则会很复杂。

请参阅 OAuth 2.0 令牌交换

使用 Microsoft Identity Web 代理流请求新的委派访问令牌

使用 Microsoft Identity Web 身份验证库 是最简单、最安全的方法。 它仅适用于 Microsoft Entra ID 和 Microsoft Entra 外部 ID。

有关详细信息,请参阅 Microsoft 标识平台和 OAuth 2.0 代理流 。

使用发送到 API 的相同委托访问令牌

此方法并不难实现,但访问令牌可以访问所有下游 API。 可以使用 Yarp 反向代理来实现这一点。

使用 OAuth 客户端凭据流并使用应用程序访问令牌

这很容易实现,但客户端应用程序拥有完全的应用程序访问权限,而不是委托访问令牌。 令牌应缓存在客户端 API 应用程序中。

注意

应用间的任何安全措施也有效。 可以使用证书身份验证,或者在 Azure 中使用托管标识。

处理访问令牌

在客户端应用程序中使用访问令牌时,必须在服务器上轮换、持久化和存储访问令牌。 在 Web 应用中,Cookie 用于保护会话,并可用于通过 SaveTokens 属性存储令牌。

SaveTokens 不会自动刷新访问令牌,但此功能计划在将来的版本中使用。 同时,可以手动刷新访问令牌,如 OIDC 文档所示Blazor Web App ,或使用第三方 NuGet 包,例如Duende.AccessTokenManagement.OpenIdConnect 。 有关详细信息,请参阅 Duende 令牌管理 。

注意

如果部署到生产环境,缓存应在多实例部署中工作。 通常需要一个持久性缓存。

某些安全令牌服务器对访问令牌进行加密。 访问令牌不需要任何格式。 使用 OAuth 内省时,请使用引用令牌而不是访问令牌。 客户端(UI)应用程序不应打开访问令牌,因为访问令牌不用于此目的。 只有该访问令牌所面向的API才应解析访问令牌。

  • 不要在 UI 应用程序中打开访问令牌。
  • 不要将 ID 令牌发送到 API。
  • 访问令牌可以采用任何格式。
  • 可以加密访问令牌。
  • 访问令牌过期,需要轮换。
  • 在安全的后端服务器上保留访问令牌。

YARP(另一种反向代理)

YARP(另一个反向代理) 是一种有用的技术,用于处理 HTTP 请求并将请求转发到其他 API。 YARP 可实现获取新访问凭据的安全逻辑。 YARP 经常用于采用前端后端(BFF)安全架构的场合。

有关 Blazor 使用 YARP 实现 BFF 模式的示例,请参阅以下文章:

Blazor有关使用 YARP 实现 BFF 模式的示例,请参阅使用 OpenID Connect 保护 ASP.NET 核心Blazor Web App(OIDC)。

有关详细信息,请参阅 auth0:Backend for Frontend 模式 。

测试 API(应用程序接口)

集成测试和带有访问令牌的容器可用于测试安全的 API。 可以使用 dotnet user-jwts 工具 来创建访问令牌。

警告

确保不会因测试目的而将安全问题引入 API 中。 当使用委托访问令牌时,测试会变得更具挑战性,因为这些令牌只能通过 UI 和 OpenID Connect 流创建。 如果使用测试工具创建委托访问令牌,则必须禁用安全功能进行测试。 必须确保仅在测试环境中禁用这些功能。

创建专用和隔离的测试环境,以便安全地禁用或修改安全功能。 确保这些更改仅限于测试环境。

使用 Swagger UI、Curl 和其他 API UI 工具

Swagger UI 和 Curl 是用于测试 API 的优秀 UI 工具。 为使工具正常工作,API 可以生成 OpenAPI 文档,客户端测试工具可以加载此文档。 可以添加安全流来获取 API OpenAPI 文件的新访问令牌。

警告

不要将不安全的安全测试流部署到生产环境。

在为 API 实现 Swagger UI 时,通常不应将 UI 部署到生产环境中,因为必须削弱安全性才能使其正常工作。

映射 OpenID Connect 中的声明

请参阅以下文档:

在 ASP.NET Core 中映射、自定义和转换声明

标准

来源与许可

作者:Damien Bowden。来源:Microsoft Learn官方中文文档,ASP.NET Core 10.0。本版保留适用版本的中文全文与代码,整理HTML排版;正文采用CC BY 4.0,示例源码许可见官方代码许可。

原始代码许可证全文
The MIT License (MIT)
Copyright (c) Microsoft Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
associated documentation files (the "Software"), to deal in the Software without restriction, 
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial 
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容