教程:从 .NET 守护程序应用调用受保护的 Web API
本教程是一整个系列的最后一部分,演示如何从 .NET 守护程序应用调用受保护的 Web API。 在本系列的第 1 部分中,你已准备好外部租户来授权 .NET 守护程序应用。 在本教程中,将构建客户端守护程序应用并调用受保护的 Web API。 启用客户端守护程序应用,使其使用自己的标识获取访问令牌,然后调用 Web API。
在本教程中;
- 配置守护程序应用以使用其应用注册详细信息。
- 构建守护程序应用,它代表其自己获取令牌并调用受保护的 Web API。
先决条件
创建 .NET 守护程序应用
打开终端并导航到希望项目所在的文件夹。
初始化 .NET 控制台应用并导航到其根文件夹。
dotnet new console -n ToDoListClient cd ToDoListClient
安装包
安装 Microsoft.Identity.Web
和 Microsoft.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 文件,并添加注册配置
在应用的根文件夹中创建 appsettings.json 文件。
将应用注册详细信息添加到 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;
}
获取访问令牌
现在,已在其中为守护程序应用程序配置了所需项目。 在此步骤中,将编写代码,使守护程序应用能够获取访问令牌。
在代码编辑器中打开 program.cs 文件并删除其内容。
将包添加到文件中。
using Microsoft.Extensions.DependencyInjection; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Web; using ToDoListClient.Models;
创建令牌获取实例。 使用
Microsoft.Identity.Web
包的TokenAcquirerFactory
类的GetDefaultInstance
方法来构建令牌获取实例。 默认情况下,如果实例与应用位于同一文件夹中,则该实例会读取 appsettings.json 文件。GetDefaultInstance
还允许将服务添加到服务集合中。将这行代码添加到 program.cs 文件中:
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
配置要从配置中读取的应用程序选项,然后添加
DownstreamApi
服务。DownstreamApi
服务提供用于调用下游 API 的接口。 在配置对象中调用此服务 DownstreamAPI。 守护程序应用从 appsettings.json 的 DownstreamApi 部分读取下游 API 配置。 默认情况下,将获得内存中的令牌缓存。将以下代码段添加到 program.cs 文件中:
const string ServiceName = "DownstreamApi"; tokenAcquirerFactory.Services.AddDownstreamApi(ServiceName, tokenAcquirerFactory.Configuration.GetSection("DownstreamApi"));
构建令牌获取器。 这将撰写添加到服务中的所有服务,并返回服务提供程序。 使用此服务提供程序可以访问添加的 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: 00aa00aa-bb11-cc22-dd33-44ee44ee44ee
Message: Bake bread
疑难解答
如果遇到错误,
- 确认添加到 appsettings.json 文件中的注册详细信息。
- 确认通过正确的端口,并通过 https 调用 Web API。
- 确认应用权限配置正确。
GitHub 上提供了完整的示例代码。
清理资源
如果不打算使用在本教程中注册和创建的应用,请删除它们以避免产生任何费用。