教程:从 .NET 守护程序应用调用受保护的 Web API

本教程是一整个系列的最后一部分,演示如何从 .NET 守护程序应用调用受保护的 Web API。 在本系列的第 1 部分中,你已准备好外部租户来授权 .NET 守护程序应用。 在本教程中,将构建客户端守护程序应用并调用受保护的 Web API。 启用客户端守护程序应用,使其使用自己的标识获取访问令牌,然后调用 Web API。

在本教程中;

  • 配置守护程序应用以使用其应用注册详细信息。
  • 构建守护程序应用,它代表其自己获取令牌并调用受保护的 Web API。

先决条件

创建 .NET 守护程序应用

  1. 打开终端并导航到希望项目所在的文件夹。

  2. 初始化 .NET 控制台应用并导航到其根文件夹。

    dotnet new console -n ToDoListClient
    cd ToDoListClient
    

安装包

安装 Microsoft.Identity.WebMicrosoft.Identity.Web.DownstreamApi 包:

dotnet add package Microsoft.Identity.Web
dotnet add package Microsoft.Identity.Web.DownstreamApi

Microsoft.Identity.Web 提供 ASP.NET Core、身份验证中间件和适用于 .NET 的 Microsoft 身份验证库 (MSAL) 之间的粘合剂,使得向应用添加身份验证和授权功能更容易。 Microsoft.Identity.Web.DownstreamApi 提供用于调用下游 API 的接口。

创建 appsettings.json 文件,并添加注册配置

  1. 在应用的根文件夹中创建 appsettings.json 文件。

  2. 将应用注册详细信息添加到 appsettings.json 文件中。

    {
        "AzureAd": {
            "Authority": "https://<Enter_the_Tenant_Subdomain_Here>.ciamlogin.com/",
            "ClientId": "<Enter_the_Application_Id_here>",
            "ClientCredentials": [
                {
                    "SourceType": "ClientSecret",
                    "ClientSecret": "<Enter_the_Client_Secret_Here>"
                }
            ]
        },
        "DownstreamApi": {
            "BaseUrl": "<Web_API_base_url>",
            "RelativePath": "api/todolist",
            "RequestAppToken": true,
            "Scopes": [
                "api://<Enter_the_Web_Api_Application_Id_Here>/.default"
            ]
        }
    }
    

    将以下值替换为你自己的值:

    说明
    Enter_the_Application_Id_Here 注册的客户端守护程序应用的应用程序(客户端)ID。
    Enter_the_Tenant_Subdomain_Here 目录(租户)子域。
    Enter_the_Client_Secret_Here 创建的守护程序应用机密值。
    Enter_the_Web_Api_Application_Id_Here 已注册 Web API 应用的应用程序(客户端)ID。
    Web_API_base_url Web API 的 基 URL。 例如,https://localhost:44351/ 其中 44351 是运行 API 的端口的端口号。 在此阶段,API 应该已经在运行并等待请求,以便获得此值。

添加模型

导航到项目文件夹的根目录,然后创建 models 文件夹。 在 models 文件夹中,创建 ToDo.cs 文件并添加以下代码:

using System;

namespace ToDoListClient.Models;

public class ToDo
{
    public int Id { get; set; }
    public Guid Owner { get; set; }
    public string Description { get; set; } = string.Empty;
}

获取访问令牌

现在,已在其中为守护程序应用程序配置了所需项目。 在此步骤中,将编写代码,使守护程序应用能够获取访问令牌。

  1. 在代码编辑器中打开 program.cs 文件并删除其内容。

  2. 将包添加到文件中。

    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Identity.Abstractions;
    using Microsoft.Identity.Web;
    using ToDoListClient.Models;
    
  3. 创建令牌获取实例。 使用 Microsoft.Identity.Web 包的 TokenAcquirerFactory 类的 GetDefaultInstance 方法来构建令牌获取实例。 默认情况下,如果实例与应用位于同一文件夹中,则该实例会读取 appsettings.json 文件。 GetDefaultInstance 还允许将服务添加到服务集合中。

    将这行代码添加到 program.cs 文件中:

    var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
    
  4. 配置要从配置中读取的应用程序选项,然后添加 DownstreamApi 服务。 DownstreamApi 服务提供用于调用下游 API 的接口。 在配置对象中调用此服务 DownstreamAPI。 守护程序应用从 appsettings.jsonDownstreamApi 部分读取下游 API 配置。 默认情况下,将获得内存中的令牌缓存。

    将以下代码段添加到 program.cs 文件中:

    const string ServiceName = "DownstreamApi";
    
    tokenAcquirerFactory.Services.AddDownstreamApi(ServiceName,
        tokenAcquirerFactory.Configuration.GetSection("DownstreamApi"));
    
    
  5. 构建令牌获取器。 这将撰写添加到服务中的所有服务,并返回服务提供程序。 使用此服务提供程序可以访问添加的 API 资源。 在这种情况下,只添加了一个 API 资源作为希望访问的下游服务。

    将以下代码段添加到 program.cs 文件中:

    var serviceProvider = tokenAcquirerFactory.Build();
    

调用 Web API

添加代码以使用 IDownstreamApi 接口调用受保护的 Web API。 在本教程中,只实现了对 Post a todo 和 Get all todos 的调用。 请参阅示例代码中的其他实现,如 Delete 和 Put。

将这行代码添加到 program.cs 文件中:

var toDoApiClient = serviceProvider.GetRequiredService<IDownstreamApi>();

Console.WriteLine("Posting a to-do...");

var firstNewToDo = await toDoApiClient.PostForAppAsync<ToDo, ToDo>(
    ServiceName,
    new ToDo()
    {
        Owner = Guid.NewGuid(),
        Description = "Bake bread"
    });

await DisplayToDosFromServer();
    
async Task DisplayToDosFromServer()
{
    Console.WriteLine("Retrieving to-do's from server...");
    var toDos = await toDoApiClient!.GetForAppAsync<IEnumerable<ToDo>>(
        ServiceName,
        options => options.RelativePath = "/api/todolist"
    );
    
    if (!toDos!.Any())
    {
        Console.WriteLine("There are no to-do's in server");
        return;
    }
    
    Console.WriteLine("To-do data:");
    
    foreach (var toDo in toDos!) {
        DisplayToDo(toDo);
    }
}

void DisplayToDo(ToDo toDo) {
    Console.WriteLine($"ID: {toDo.Id}");
    Console.WriteLine($"User ID: {toDo.Owner}");
    Console.WriteLine($"Message: {toDo.Description}");
}

运行客户端守护程序应用

导航到守护程序应用的根文件夹并运行以下命令:

dotnet run

如果一切正常,应该在终端中看到以下输出。

Posting a to-do...
Retrieving to-do's from server...
To-do data:
ID: 1
User ID: 00001111-aaaa-2222-bbbb-3333cccc4444

Message: Bake bread

疑难解答

如果遇到错误,

  • 确认添加到 appsettings.json 文件中的注册详细信息。
  • 确认通过正确的端口,并通过 https 调用 Web API。
  • 确认应用权限配置正确。

GitHub 上提供了完整的示例代码。

清理资源

如果不打算使用在本教程中注册和创建的应用,请删除它们以避免产生任何费用。

另请参阅