测试受保护的 ASP.NET 核心 Web API

本教程是一系列教程的最后一部分,演示如何生成和测试在 Microsoft Entra 租户中注册的受保护 Web API。 在本系列的第 1 部分中,你创建了一个 ASP.NET 核心 Web API 并保护其终结点。 现在,你将创建一个轻型守护程序应用,在租户中注册它,并使用守护程序应用测试生成的 Web API。

本教程中,您将学习如何:

  • 注册守护程序应用
  • 为守护程序应用分配应用角色
  • 生成守护程序应用
  • 运行守护程序应用以调用受保护的 Web API

先决条件

  • 如果尚未完成教程,请通过微软身份验证平台生成并保护 ASP.NET Core Web API

注册守护程序应用

以下步骤演示如何在 Microsoft Entra 管理中心注册守护程序应用:

  1. 至少以应用程序开发人员的身份登录到 Microsoft Entra 管理中心

  2. 如果有权访问多个租户,请使用顶部菜单中的 “设置” 图标从 “目录 + 订阅 ”菜单切换到租户。

  3. 浏览到“标识”“应用程序”>“应用注册”>

  4. 选择“+ 新建注册”。

  5. 在出现的“注册应用程序”页面中,输入应用程序的注册信息:

    1. 在“名称”部分中,输入将向应用用户显示的有意义的应用程序名称,例如“ciam-client-app”。

    2. 在“支持的帐户类型”下,选择“仅此组织目录中的帐户”。

  6. 选择“注册”。

  7. 注册完成后,将显示应用程序的“概述”窗格。 记录要用于应用程序源代码的目录(租户)ID应用程序(客户端)ID

为注册的应用创建客户端机密。 应用程序在请求令牌时使用客户端密码来证明其标识:

  1. “应用注册 ”页中,选择你创建的应用程序(如 Web 应用客户端密码)以打开其 “概述 ”页。
  2. 在“ 管理”下,选择“ 证书和机密>客户端机密>”新建客户端机密
  3. “说明 ”框中,输入客户端密码的说明(例如 Web 应用客户端密码)。
  4. 在“过期时间”下,选择密码的有效期(根据组织的安全规则),然后选择“添加”。
  5. 记下机密的“值”。 您将在后续步骤中将此值用于配置。 离开“证书和机密”后,机密值不会再次显示,并且无法以任何方式检索。 请确保记录它。

为守护程序应用分配应用角色

无需用户即可自行进行身份验证的应用程序需要应用权限(也称为角色)。 这些权限允许应用本身直接访问资源。 另一方面,如果我们使用已登录用户测试 API,我们将分配委派的权限(范围)。 委派的权限使应用能够代表用户执行作,仅限于用户的访问权限。 按照以下步骤将应用程序权限分配给守护程序应用:

  1. 从“应用注册”页中,选择创建的应用程序(例如 ciam-client-app)。

  2. 在“ 管理”下,选择 API 权限

  3. 在“已配置权限”下,选择“添加权限”。

  4. 选择“我的组织使用的 API”选项卡。

  5. 在 API 列表中,选择 API(例如 ciam-ToDoList-api)。

  6. 选择“应用程序权限”选项。 我们选择此选项是因为应用以自身身份登录,而不是以用户身份登录。

  7. 从权限列表中,选择“TodoList.Read.All”、“ToDoList.ReadWrite.All”(必要时使用搜索框)。

  8. 选择“添加权限”按钮。

  9. 此时,你已正确分配了权限。 但是,由于守护程序应用不允许用户与之交互,因此用户本身无法同意这些权限。 若要解决此问题,作为管理员的你必须代表租户中的所有用户同意这些权限:

    1. 选择“为<租户名称>授予管理员同意”,然后选择“是”。
    2. 选择“刷新”,然后验证两个权限的“状态”下是否均显示“已为 租户名称< 授予”>

生成守护程序应用

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

    dotnet new console -o MyTestApp
    cd MyTestApp
    
  2. 通过运行以下命令安装 MSAL.NET 来帮助处理身份验证:

    dotnet add package Microsoft.Identity.Client
    
  3. 运行你的 API 项目并记下它运行的端口。

  4. 打开 Program.cs 文件,将“Hello world”代码替换为以下代码。

    using System;
    using System.Net.Http;
    using System.Net.Http.Headers;
    
    HttpClient client = new HttpClient();
    
    var response = await client.GetAsync("http://localhost:<your-api-port>/api/todolist);
    Console.WriteLine("Your response is: " + response.StatusCode);
    

    导航到守护程序应用根目录,使用命令 dotnet run 运行应用。 此代码发送一个没有访问令牌的请求。 你应该会在控制台中看到字符串“你的响应是: 未授权”。

  5. 删除步骤 4 中的代码,将其替换为以下代码,以通过发送一个具有有效访问令牌的请求来测试你的 API。 此守护程序应用使用客户端凭据流获取访问令牌,因为它无需用户交互即可进行身份验证。

    using Microsoft.Identity.Client;
    using System;
    using System.Net.Http;
    using System.Net.Http.Headers;
    
    HttpClient client = new HttpClient();
    
    var clientId = "<your-daemon-app-client-id>";
    var clientSecret = "<your-daemon-app-secret>";
    var scopes = new[] {"api://<your-web-api-application-id>/.default"};
    var tenantId = "<your-tenant-id>";     //Use in workforce tenant configuration
    var authority = $"https://login.partner.microsoftonline.cn/{tenantId}"; 
    
    var app = ConfidentialClientApplicationBuilder
        .Create(clientId)
        .WithAuthority(authority)
        .WithClientSecret(clientSecret)
        .Build();
    
    var result = await app.AcquireTokenForClient(new string[] { scopes }).ExecuteAsync();
    Console.WriteLine($"Access Token: {result.AccessToken}");
    
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
    var response = await client.GetAsync("http://localhost:/<your-api-port>/api/todolist");
    var content = await response.Content.ReadAsStringAsync();
    
    Console.WriteLine("Your response is: " + response.StatusCode);
    Console.WriteLine(content);
    
  6. 将代码中的占位符替换为守护程序应用客户端 ID、机密、Web API 应用程序 ID 和租户名称。

    • 对于工作人员租户,请在表单中使用授权:"https://login.partner.microsoftonline.cn/{tenantId}"
  7. 导航到守护程序应用根目录,使用命令 dotnet run 运行应用。 此代码发送一个具有有效访问令牌的请求。 你应该会在控制台中看到字符串“你的响应是: 正常”。