受保护的 Web API:代码配置Protected web API: Code configuration

若要配置受保护 Web API 的代码,需要了解:To configure the code for your protected web API, you need to understand:

  • API 受保护的定义是什么。What defines APIs as protected.
  • 如何配置持有者令牌。How to configure a bearer token.
  • 如何验证令牌。How to validate the token.

ASP.NET 和 ASP.NET Core API 受保护是什么意思?What defines ASP.NET and ASP.NET Core APIs as protected?

与 Web 应用一样,ASP.NET 和 ASP.NET Core Web API 也受到保护,因为它们的控制器操作以 [Authorize] 属性为前缀。Like web apps, the ASP.NET and ASP.NET Core web APIs are protected because their controller actions are prefixed with the [Authorize] attribute. 仅当使用已授权的标识调用 API 时,才能调用控制器操作。The controller actions can be called only if the API is called with an authorized identity.

考虑以下问题:Consider the following questions:

  • 只有应用可以调用 Web API。Only an app can call a web API. API 如何识别调用它的应用的标识?How does the API know the identity of the app that calls it?
  • 如果应用代表某个用户调用 API,该用户的标识是什么?If the app calls the API on behalf of a user, what's the user's identity?

持有者令牌Bearer token

调用应用时在标头中设置的持有者令牌包含有关应用标识的信息。The bearer token that's set in the header when the app is called holds information about the app identity. 除非 Web 应用接受来自守护程序应用的服务到服务调用,否则该令牌还包含有关用户的信息。It also holds information about the user unless the web app accepts service-to-service calls from a daemon app.

以下 C# 代码示例演示了某个客户端在使用适用于 .NET 的 Microsoft 身份验证库 (MSAL.NET) 获取令牌后调用 API:Here's a C# code example that shows a client calling the API after it acquires a token with Microsoft Authentication Library for .NET (MSAL.NET):

var scopes = new[] {$"api://.../access_as_user"};
var result = await app.AcquireToken(scopes)
                      .ExecuteAsync();

httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

// Call the web API.
HttpResponseMessage response = await _httpClient.GetAsync(apiUri);

重要

客户端应用程序向 Web API 的 Microsoft 标识平台终结点请求持有者令牌。 A client application requests the bearer token to the Microsoft identity platform endpoint for the web API. Web API 是唯一应该验证令牌并查看其中包含的声明的应用程序。The web API is the only application that should verify the token and view the claims it contains. 客户端应用永远不会尝试检查令牌中的声明。Client apps should never try to inspect the claims in tokens.

将来,Web API 可能要求加密令牌。In the future, the web API might require that the token be encrypted. 这项要求会阻止可以查看访问令牌的客户端应用进行访问。This requirement would prevent access for client apps that can view access tokens.

JwtBearer 配置JwtBearer configuration

本部分介绍如何配置持有者令牌。This section describes how to configure a bearer token.

配置文件Config file

{
  "AzureAd": {
    "Instance": "https://login.partner.microsoftonline.cn/",
    "ClientId": "[Client_id-of-web-api-eg-2ec40e65-ba09-4853-bcde-bcb60029e596]",
    /*
      You need specify the TenantId only if you want to accept access tokens from a single tenant
     (line-of-business app).
      Otherwise, you can leave them set to common.
      This can be:
      - A GUID (Tenant ID = Directory ID)
      - 'common' (any organization)
      - 'organizations' (any organization)
    */
    "TenantId": "common"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

为 Web API 使用自定义应用 ID URI 时Case where you used a custom App ID URI for your web API

如果已接受门户建议的应用 ID URI,则无需指定受众(请参阅应用程序 ID URI 和作用域)。If you've accepted the App ID URI proposed by the portal, you don't need to specify the audience (see Application ID URI and scopes). 否则,应添加一个 Audience 属性,其值为 Web API 的应用 ID URI。Otherwise, you should add an Audience property whose value is the App ID URI for your web API.

{
  "AzureAd": {
    "Instance": "https://login.partner.microsoftonline.cn/",
    "ClientId": "[Client_id-of-web-api-eg-2ec40e65-ba09-4853-bcde-bcb60029e596]",
    "TenantId": "common",
    "Audience": "custom App ID URI for your web API"
  },
  // more lines
}

代码初始化Code initialization

对包含 [Authorize] 属性的控制器操作调用某个应用时,ASP.NET 和 ASP.NET Core 将从 Authorization 标头的持有者令牌中提取访问令牌。When an app is called on a controller action that holds an [Authorize] attribute, ASP.NET and ASP.NET Core extract the access token from the Authorization header's bearer token. 然后,该访问令牌将转发到 JwtBearer 中间件,而该中间件会调用适用于 .NET 的 Microsoft IdentityModel 扩展。The access token is then forwarded to the JwtBearer middleware, which calls Microsoft IdentityModel Extensions for .NET.

使用 Microsoft.Identity.Web 模板Using Microsoft.Identity.Web templates

可以通过使用 Microsoft.Identity.Web 项目模板从头开始创建一个 Web API。You can create a web API from scratch by using Microsoft.Identity.Web project templates. 有关详细信息,请参阅 Microsoft.Identity.Web - Web API 项目模板For details see Microsoft.Identity.Web - Web API project template

从现有 ASP.NET Core 3.1 应用程序开始Starting from an existing ASP.NET Core 3.1 application

目前,ASP.NET Core 3.1 使用 Microsoft.AspNetCore.AzureAD.UI 库。Today, ASP.NET Core 3.1 uses the Microsoft.AspNetCore.AzureAD.UI library. 该中间件在 Startup.cs 文件中初始化。The middleware is initialized in the Startup.cs file.

using Microsoft.AspNetCore.Authentication.JwtBearer;

该中间件由以下指令添加到 Web API:The middleware is added to the web API by this instruction:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
  services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme)
          .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
}

目前,ASP.NET Core 模板会创建可将你的组织或任何组织中的用户登录的 Azure Active Directory (Azure AD) Web API。Currently, the ASP.NET Core templates create Azure Active Directory (Azure AD) web APIs that sign in users within your organization or any organization. 可以将模板更改为使用 Microsoft 身份平台终结点,方法是使用 Microsoft.Identity.Web(以 NuGet 包的形式)替换 Startup.cs 中的代码:You can change the templates to use the Microsoft identity platform endpoint by using Microsoft.Identity.Web, available as a NuGet package, replacing the code in Startup.cs:

using Microsoft.Identity.Web;
public void ConfigureServices(IServiceCollection services)
{
 // Adds Microsoft Identity platform (AAD v2.0) support to protect this API
 services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAd");

 services.AddControllers();
}

备注

如果使用 Microsoft.Identity.Web,但未在 appsettings.json 中设置 Audience,则使用以下内容:If you use Microsoft.Identity.Web and don't set the Audience in appsettings.json, the following is used:

前面的代码段摘自 ASP.NET Core Web API 增量教程The preceding code snippet is extracted from the ASP.NET Core web API incremental tutorial. Microsoft.Identity.Web 中提供了“AddMicrosoftWebApiAuthentication”的详细信息。The detail of AddMicrosoftWebApiAuthentication is available in Microsoft.Identity.Web. 此方法调用 AddMicrosoftWebAPI,后者会指示中间件如何验证令牌。This method calls AddMicrosoftWebAPI, which itself instructs the middleware on how to validate the token. 有关详细信息,请参阅其源代码For details see its source code.

令牌验证Token validation

在上述代码片段中,与 Web 应用中的 OpenID Connect 中间件一样,JwtBearer 中间件将会根据 TokenValidationParameters 的值验证令牌。In the preceding snippet, the JwtBearer middleware, like the OpenID Connect middleware in web apps, validates the token based on the value of TokenValidationParameters. 根据需要解密该令牌,提取声明,并验证签名。The token is decrypted as needed, the claims are extracted, and the signature is verified. 然后,该中间件将通过检查以下数据来验证该令牌:The middleware then validates the token by checking for this data:

  • 受众:令牌面向 Web API。Audience: The token is targeted for the web API.
  • 使用者:令牌是针对可以调用 Web API 的应用颁发的。Sub: It was issued for an app that's allowed to call the web API.
  • 颁发者:令牌是由受信任的安全令牌服务 (STS) 颁发的。Issuer: It was issued by a trusted security token service (STS).
  • 过期时间:令牌的生存期在有效范围内。Expiry: Its lifetime is in range.
  • 签名:令牌未被篡改。Signature: It wasn't tampered with.

此外还可以执行特殊验证。There can also be special validations. 例如,可以验证嵌入在令牌中的签名密钥是否受信任,以及令牌是否未重放。For example, it's possible to validate that signing keys, when embedded in a token, are trusted and that the token isn't being replayed. 最后,某些协议需要特定的验证。Finally, some protocols require specific validations.

验证程序Validators

适用于 .NET 的 Microsoft 标识模型扩展开源库提供的验证程序中捕获验证步骤。The validation steps are captured in validators, which are provided by the Microsoft IdentityModel Extensions for .NET open-source library. 验证程序在库源文件 Microsoft.IdentityModel.Tokens/Validators.cs 中定义。The validators are defined in the library source file Microsoft.IdentityModel.Tokens/Validators.cs.

下表描述了验证程序:This table describes the validators:

验证程序Validator 说明Description
ValidateAudienceValidateAudience 确保该令牌适用于为你验证令牌的应用程序。Ensures the token is for the application that validates the token for you.
ValidateIssuerValidateIssuer 确保令牌由受信任的 STS 颁发,即,令牌来自你信任的某人。Ensures the token was issued by a trusted STS, meaning it's from someone you trust.
ValidateIssuerSigningKeyValidateIssuerSigningKey 确保验证令牌的应用程序信任用于签署令牌的密钥。Ensures the application validating the token trusts the key that was used to sign the token. 在令牌中嵌入密钥存在一种特殊情况。There's a special case where the key is embedded in the token. 但这种情况通常不会出现。But this case doesn't usually arise.
ValidateLifetimeValidateLifetime 确保令牌仍然或已经生效。Ensures the token is still or already valid. 验证程序将检查令牌的生存期是否在 notbeforeexpires 声明指定的范围内。The validator checks if the lifetime of the token is in the range specified by the notbefore and expires claims.
ValidateSignatureValidateSignature 确保令牌未被篡改。Ensures the token hasn't been tampered with.
ValidateTokenReplayValidateTokenReplay 确保令牌未重放。Ensures the token isn't replayed. 某些一次性协议存在一种特殊情况。There's a special case for some onetime-use protocols.

自定义令牌验证Customizing token validation

验证程序与 TokenValidationParameters 类的属性相关联。The validators are associated with properties of the TokenValidationParameters class. 这些属性从 ASP.NET 和 ASP.NET Core 配置初始化。The properties are initialized from the ASP.NET and ASP.NET Core configuration.

在大多数情况下,无需更改参数,In most cases, you don't need to change the parameters. 非单租户应用除外。Apps that aren't single tenants are exceptions. 这些 Web 应用接受任何组织帐户中的用户。These web apps accept users from any organization accounts. 对于这种情况,必须验证颁发者。Issuers in this case must be validated. Microsoft.Identity.Web 还负责颁发者验证。Microsoft.Identity.Web takes care of the issuer validation as well. 有关详细信息,请参阅 Microsoft.Identity.Web AadIssuerValidatorFor details see Microsoft.Identity.Web AadIssuerValidator.

在 ASP.NET Core 中,如果要自定义令牌验证参数,请在 Startup.cs 中使用以下代码片段:In ASP.NET Core, if you want to customize the token validation parameters, use the following snippet in your Startup.cs:

services.AddMicrosoftWebApiAuthentication(Configuration);
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
  var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;
  options.Events.OnTokenValidated = async context =>
  {
       await existingOnTokenValidatedHandler(context);
      // Your code to add extra configuration that will be executed after the current event implementation.
      options.TokenValidationParameters.ValidIssuers = new[] { /* list of valid issuers */ };
      options.TokenValidationParameters.ValidAudiences = new[] { /* list of valid audiences */};
  }
});

对于 ASP.NET MVC,下面的代码示例演示了如何执行自定义令牌验证:For ASP.NET MVC, the following code sample shows how to do custom token validation:

https://github.com/azure-samples/active-directory-dotnet-webapi-manual-jwt-validation

Azure Functions 中的令牌验证Token validation in Azure Functions

还可以在 Azure Functions 中验证传入的访问令牌。You can also validate incoming access tokens in Azure Functions. 可以在 GitHub 上的以下代码示例中找到此类验证的示例:You can find examples of such validation in the following code samples on GitHub:

后续步骤Next steps