调用 Web API 的 Web 应用:代码配置A web app that calls web APIs: Code configuration

用于登录用户的 Web 应用方案中所述,Web 应用使用 OAuth 2.0 授权代码流来登录用户。As shown in the Web app that signs in users scenario, the web app uses the OAuth 2.0 authorization code flow to sign the user in. 此流有两个步骤:This flow has two steps:

  1. 请求获取授权代码。Request an authorization code. 此部分将私密对话和用户一起委派给 Microsoft 标识平台。This part delegates a private dialogue with the user to the Microsoft identity platform. 在此对话期间,用户登录,并同意使用 Web API。During that dialogue, the user signs in and consents to the use of web APIs. 当此私密对话成功结束时,Web 应用会在其重定向 URI 中收到一个授权代码。When the private dialogue ends successfully, the web app receives an authorization code on its redirect URI.
  2. 通过兑换授权代码来请求获取 API 的访问令牌。Request an access token for the API by redeeming the authorization code.

用于登录用户的 Web 应用方案只涉及第一步。The Web app that signs in users scenarios covered only the first step. 在本文中,你将学习如何修改 Web 应用,使其不仅能登录用户,而且现在还能调用 Web API。Here you learn how to modify your web app so that it not only signs users in but also now calls web APIs.

支持 Web 应用方案的库Libraries that support web-app scenarios

Microsoft 身份验证库 (MSAL) 中的以下库支持 Web 应用的授权代码流:The following libraries in the Microsoft Authentication Library (MSAL) support the authorization code flow for web apps:

MSAL 库MSAL library 说明Description
MSAL.NET
MSAL.NETMSAL.NET
支持 .NET Framework 和 .NET Core 平台。Support for .NET Framework and .NET Core platforms. 不支持通用 Windows 平台 (UWP)、Xamarin.iOS 和 Xamarin.Android,因为这些平台用于生成公共客户端应用。Not supported are Universal Windows Platform (UWP), Xamarin.iOS, and Xamarin.Android, because those platforms are used to build public client applications.

对于 ASP.NET Core Web 应用和 Web API,MSAL.NET 会封装在名为 Microsoft.Identity.Web 的更高级别库中。For ASP.NET Core web apps and web APIs, MSAL.NET is encapsulated in a higher-level library named Microsoft.Identity.Web.
MSAL Python
适用于 Python 的 MSALMSAL for Python
支持 Python Web 应用。Support for Python web applications.
MSAL Java
适用于 Java 的 MSALMSAL for Java
支持 Java Web 应用。Support for Java web applications.

选择你感兴趣的平台的选项卡:Select the tab for the platform you're interested in:

客户端密码或客户端证书Client secrets or client certificates

鉴于 Web 应用现在调用下游 Web API,你需要在 appsettings.json 文件中提供客户端密码或客户端证书。Given that your web app now calls a downstream web API, you need to provide a client secret or client certificate in the appsettings.json file. 你还可以添加一个节来指定:You can also add a section that specifies:

  • 下游 Web API 的 URLThe URL of the downstream web API
  • 调用 API 所需的范围The scopes required for calling the API

在下面的示例中,GraphBeta 节指定了这些设置。In the following example, the GraphBeta section specifies these settings.

{
  "AzureAd": {
    "Instance": "https://login.partner.microsoftonline.cn/",
    "ClientId": "[Client_id-of-web-app-eg-2ec40e65-ba09-4853-bcde-bcb60029e596]",
    "TenantId": "common"

   // To call an API
   "ClientSecret": "[Copy the client secret added to the app from the Azure portal]",
   "ClientCertificates": [
  ]
 },
 "GraphBeta": {
    "BaseUrl": "https://microsoftgraph.chinacloudapi.cn/beta",
    "Scopes": "https://microsoftgraph.chinacloudapi.cn/user.read"
    }
}

你可以提供客户端证书,而不是客户端密码。Instead of a client secret, you can provide a client certificate. 以下代码片段演示如何使用存储在 Azure Key Vault 中的证书。The following code snippet shows using a certificate stored in Azure Key Vault.

{
  "AzureAd": {
    "Instance": "https://login.partner.microsoftonline.cn/",
    "ClientId": "[Client_id-of-web-app-eg-2ec40e65-ba09-4853-bcde-bcb60029e596]",
    "TenantId": "common"

   // To call an API
   "ClientCertificates": [
      {
        "SourceType": "KeyVault",
        "KeyVaultUrl": "https://msidentitywebsamples.vault.azure.cn",
        "KeyVaultCertificateName": "MicrosoftIdentitySamplesCert"
      }
   ]
  },
  "GraphBeta": {
    "BaseUrl": "https://microsoftgraph.chinacloudapi.cn/beta",
    "Scopes": "https://microsoftgraph.chinacloudapi.cn/user.read"
  }
}

Microsoft.Identity.Web 提供了多种通过配置或代码描述证书的方法。Microsoft.Identity.Web provides several ways to describe certificates, both by configuration or by code. 有关详细信息,请参阅 GitHub 上的 Microsoft.Identity.Web - 使用证书For details, see Microsoft.Identity.Web - Using certificates on GitHub.

Startup.csStartup.cs

Web 应用将需要获取下游 API 的令牌。Your web app will need to acquire a token for the downstream API. 可通过在 .AddMicrosoftIdentityWebApi(Configuration) 后面添加 .EnableTokenAcquisitionToCallDownstreamApi() 行来指定它。You specify it by adding the .EnableTokenAcquisitionToCallDownstreamApi() line after .AddMicrosoftIdentityWebApi(Configuration). 此行公开 ITokenAcquisition 服务,可在控制器和页面操作中使用该服务。This line exposes the ITokenAcquisition service that you can use in your controller and page actions. 不过,正如你将在以下两个选项中看到的那样,可以更简单地执行此操作。However, as you'll see in the following two options, it can be done more simply. 还需要在 Startup.cs 中选择令牌缓存实现,例如 .AddInMemoryTokenCaches()You'll also need to choose a token cache implementation, for example .AddInMemoryTokenCaches(), in Startup.cs:

using Microsoft.Identity.Web;

public class Startup
{
  // ...
  public void ConfigureServices(IServiceCollection services)
  {
  // ...
  services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
          .AddMicrosoftIdentityWebApp(Configuration, Configuration.GetSection("AzureAd"))
            .EnableTokenAcquisitionToCallDownstreamApi(new string[]{"user.read" })
            .AddInMemoryTokenCaches();
   // ...
  }
  // ...
}

传递给 EnableTokenAcquisitionToCallDownstreamApi 的范围是可选项,使 Web 应用能够请求范围并在用户登录时向用户征求对这些范围的许可。The scopes passed to EnableTokenAcquisitionToCallDownstreamApi are optional, and enable your web app to request the scopes and the user's consent to those scopes when they log in. 如果未指定范围,Microsoft.Identity.Web 会启用增量许可体验。If you don't specify the scopes, Microsoft.Identity.Web will enable an incremental consent experience.

如果你不想自行获取令牌,可以通过 Microsoft.Identity.Web 提供的两种机制从 Web 应用调用 Web API。If you don't want to acquire the token yourself, Microsoft.Identity.Web provides two mechanisms for calling a web API from a web app. 选择哪种机制取决于你是要调用 Microsoft Graph 还是调用另一个 API。The option you choose depends on whether you want to call Microsoft Graph or another API.

选项 1:调用 Microsoft GraphOption 1: Call Microsoft Graph

如果要调用 Microsoft Graph,则可通过 Microsoft.Identity.Web 在 API 操作中直接使用 GraphServiceClient(由 Microsoft Graph SDK 公开)。If you want to call Microsoft Graph, Microsoft.Identity.Web enables you to directly use the GraphServiceClient (exposed by the Microsoft Graph SDK) in your API actions. 若要公开 Microsoft Graph,请执行以下操作:To expose Microsoft Graph:

  1. Microsoft.Identity.Web.MicrosoftGraph NuGet 包添加到项目。Add the Microsoft.Identity.Web.MicrosoftGraph NuGet package to your project.

  2. 在 Startup.cs 文件的 .EnableTokenAcquisitionToCallDownstreamApi() 后面添加 .AddMicrosoftGraph()Add .AddMicrosoftGraph() after .EnableTokenAcquisitionToCallDownstreamApi() in the Startup.cs file. .AddMicrosoftGraph() 具有多个重写。.AddMicrosoftGraph() has several overrides. 使用将配置部分作为参数的重写,代码变为:Using the override that takes a configuration section as a parameter, the code becomes:

    using Microsoft.Identity.Web;
    
    public class Startup
    {
      // ...
      public void ConfigureServices(IServiceCollection services)
      {
      // ...
      services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
              .AddMicrosoftIdentityWebApp(Configuration, Configuration.GetSection("AzureAd"))
                .EnableTokenAcquisitionToCallDownstreamApi(new string[]{"user.read" })
                   .AddMicrosoftGraph(Configuration.GetSection("GraphBeta"))
                .AddInMemoryTokenCaches();
       // ...
      }
      // ...
    }
    

选项 2:调用下游 Web API 而不是 Microsoft GraphOption 2: Call a downstream web API other than Microsoft Graph

为了调用 Web API 而不是 Microsoft Graph,Microsoft.Identity.Web 提供了 .AddDownstreamWebApi(),它可请求令牌并调用下游 Web API。To call a web API other than Microsoft Graph, Microsoft.Identity.Web provides .AddDownstreamWebApi(), which requests tokens and calls the downstream web API.

using Microsoft.Identity.Web;

public class Startup
{
  // ...
  public void ConfigureServices(IServiceCollection services)
  {
  // ...
  services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
          .AddMicrosoftIdentityWebApp(Configuration, "AzureAd")
            .EnableTokenAcquisitionToCallDownstreamApi(new string[]{"user.read" })
               .AddDownstreamWebApi("MyApi", Configuration.GetSection("GraphBeta"))
            .AddInMemoryTokenCaches();
   // ...
  }
  // ...
}

总结Summary

与 Web API 一样,你可以选择各种令牌缓存实现。As with web APIs, you can choose various token cache implementations. 有关详细信息,请参阅 GitHub 上的 Microsoft.Identity.Web - 令牌缓存序列化For details, see Microsoft.Identity.Web - Token cache serialization on GitHub.

下图显示 Microsoft.Identity.Web 的各种可能性及其对 Startup.cs 文件的影响 :The following image shows the various possibilities of Microsoft.Identity.Web and their impact on the Startup.cs file:

此框图显示了 Startup.cs 中的服务配置选项,用于调用 Web API 和指定令牌缓存实现

备注

若要完全理解本文中的代码示例,需要熟悉 ASP.NET Core 基础知识,尤其是依赖关系注入选项To fully understand the code examples here, you need to be familiar with ASP.NET Core fundamentals, and in particular with dependency injection and options.

兑换授权代码的代码Code that redeems the authorization code

Microsoft.Identity.Web 通过设置正确的 OpenID Connect 设置、订阅代码接收的事件和兑换代码来简化代码。Microsoft.Identity.Web simplifies your code by setting the correct OpenID Connect settings, subscribing to the code received event, and redeeming the code. 兑换授权代码不需要其他任何代码。No additional code is required to redeem the authorization code. 请参阅 Microsoft.Identity.Web 源代码,详细了解其原理。See Microsoft.Identity.Web source code for details on how this works.

保密客户端应用还可以使用客户端证书或客户端断言(而不是客户端密码)来证明其标识。Instead of a client secret, the confidential client application can also prove its identity by using a client certificate, or a client assertion. 使用客户端断言是一种高级方案,客户端断言中对此进行了详细说明。The use of client assertions is an advanced scenario, detailed in Client assertions.

令牌缓存Token cache

重要

Web 应用或 Web API 的令牌缓存实现不同于桌面应用的实现,后者通常是基于文件的。The token-cache implementation for web apps or web APIs is different from the implementation for desktop applications, which is often file based. 出于安全性和性能方面的原因,请务必确保对于 Web 应用和 Web API,每个用户帐户都有一个令牌缓存。For security and performance reasons, it's important to ensure that for web apps and web APIs there is one token cache per user account. 必须为每个帐户序列化令牌缓存。You must serialize the token cache for each account.

ASP.NET Core 教程使用依赖关系注入,让你能够在应用的 Startup.cs 文件中确定令牌缓存实现。The ASP.NET core tutorial uses dependency injection to let you decide the token cache implementation in the Startup.cs file for your application. Microsoft.Identity.Web 随附了令牌缓存序列化中所述的预生成令牌缓存序列化程序。Microsoft.Identity.Web comes with pre-built token-cache serializers described in Token cache serialization. 一个有意思的地方是,可以选择 ASP.NET Core 分布式内存缓存An interesting possibility is to choose ASP.NET Core distributed memory caches:

// Use a distributed token cache by adding:
    services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAd")
            .EnableTokenAcquisitionToCallDownstreamApi(
                initialScopes: new string[] { "https://microsoftgraph.chinacloudapi.cn/user.read" })
            .AddDistributedTokenCaches();

// Then, choose your implementation.
// For instance, the distributed in-memory cache (not cleared when you stop the app):
services.AddDistributedMemoryCache();

// Or a Redis cache:
services.AddStackExchangeRedisCache(options =>
{
 options.Configuration = "localhost";
 options.InstanceName = "SampleInstance";
});

// Or even a SQL Server token cache:
services.AddDistributedSqlServerCache(options =>
{
 options.ConnectionString = _config["DistCache_ConnectionString"];
 options.SchemaName = "dbo";
 options.TableName = "TestCache";
});

有关令牌缓存提供程序的详细信息,另请参阅 Microsoft.Identity.Web 的令牌缓存序列化一文,以及 Web 应用教程的 ASP.NET Core Web 应用教程 | 令牌缓存部分。For details about the token-cache providers, see also Microsoft.Identity.Web's Token cache serialization article, as well as the ASP.NET Core Web app tutorials | Token caches phase of the web apps tutorial.

后续步骤Next steps

此时,当用户登录时,令牌存储在令牌缓存中。At this point, when the user signs in, a token is stored in the token cache. 让我们来看看随后是如何在 Web 应用的其他部分中使用它的。Let's see how it's then used in other parts of the web app.

在全局注销时从缓存中删除帐户Remove accounts from the cache on global sign-out