在本地开发期间使用服务主体对访问 Azure 服务的 .NET 应用进行身份验证

在创建云应用程序时,开发人员需要在其本地工作站上调试和测试应用程序。 在本地开发期间,当应用程序在开发人员的工作站上运行时,它仍然必须向应用使用的任何 Azure 服务进行身份验证。 本文介绍如何设置要在本地开发期间使用的专用应用程序服务主体对象。

该图显示了在本地开发期间 .NET 应用程序如何使用开发人员的凭据连接到 Azure,以及如何使用本地安装的开发工具获取这些凭据。

使用用于本地开发的专用应用程序服务主体可以在应用开发期间遵循最低特权原则。 由于权限的范围严格限定为开发期间应用所需的权限,因此可以防止应用代码意外访问仅供其他应用使用的 Azure 资源。 在将应用转移到生产环境时,这还可以防止出现 bug,因为该应用在开发环境中特权过高。

在 Azure 中注册应用时,将为该应用设置应用程序服务主体。 为本地开发注册应用时,建议:

  • 为每个处理该应用的开发人员单独创建应用注册。 这会为每个开发人员单独创建要在本地开发期间使用的应用程序服务主体,并避免开发人员共享单个应用程序服务主体的凭据的需要。
  • 为每个应用单独创建应用注册。 这会将应用的权限范围限定为该应用所需的权限。

在本地开发期间,将使用应用程序服务主体的标识设置环境变量。 Azure SDK for NET 读取这些环境变量,并使用此信息对访问所需 Azure 资源的应用进行身份验证。

1 - 在 Azure 中注册应用程序

应用程序服务主体对象是使用 Azure 中的应用注册创建的。 可以使用 Azure 门户或 Azure CLI 完成此操作。

登录到 Azure 门户并执行以下步骤。

说明 屏幕快照
在 Azure 门户中:
  1. 在 Azure 门户顶部的搜索栏中输入“应用注册”。
  2. 在搜索栏下方显示的菜单中的“服务”标题下,选择标有“应用注册”的项。
显示如何使用 Azure 门户中的顶部搜索栏查找并导航到“应用注册”页的屏幕截图。
在“应用注册”页上,选择“+ 新建注册”。 显示“新建注册”按钮在“应用注册”页中的位置的屏幕截图。
在“注册应用程序”页上,按如下所示填写窗体。
  1. 名称 → 输入该应用注册在 Azure 中的名称。 建议在此名称中包含应用名称、应用注册所针对的用户,以及类似于“dev”的标识符,以指示此应用注册用于本地开发。
  2. 支持的帐户类型 → 仅限此组织目录中的帐户。
选择“注册”以注册应用并创建应用程序服务主体。
显示如何填写“注册应用程序”页的屏幕截图:为应用命名,并将“支持的帐户类型”指定为“仅限此组织目录中的帐户”。
在应用的“应用注册”页上:
  1. 应用程序(客户端) ID → 这是在本地开发期间由应用用来访问 Azure 的应用 ID。 将此值复制到文本编辑器中的临时位置,因为在稍后的步骤中需要用到。
  2. 目录(租户) ID → 应用在向 Azure 进行身份验证时也需要此值。 将此值复制到文本编辑器中的临时位置,因为在稍后的步骤中也需要用到。
  3. 客户端凭据 → 必须先为应用设置客户端凭据,然后应用才能向 Azure 进行身份验证并使用 Azure 服务。 选择“添加证书或机密”以添加应用的凭据。
完成应用注册后的“应用注册”页的屏幕截图。此屏幕截图显示了应用程序 ID 和租户 ID 的位置,在稍后的步骤中需要用到。它还显示了用来为应用添加应用程序机密的链接的位置。
在“证书和机密”页上,选择“+ 新建客户端密码”。 显示“证书和机密”页上用于创建新客户端机密的链接的位置的屏幕截图。
页面右侧会弹出“添加客户端机密”对话框。 在此对话框中:
  1. 说明 → 输入值“当前”。
  2. 过期时间 → 选择值“24 个月”。
选择“添加”以添加机密。
显示为应用注册过程创建的应用程序服务主体添加了新客户端机密的页面的屏幕截图。
在“证书和机密”页上,你将看到客户端密码的值。

将此值复制到文本编辑器中的临时位置,因为在稍后的步骤中需要用到。

重要说明:此值只会显示一次。一旦你离开或刷新此页,将不再可以看到此值。 可以在不使此客户端机密失效的情况下添加一个额外的客户端机密,但不再可以看到此值。
显示包含生成的客户端机密的页面的屏幕截图。

2 - 为本地开发创建 Azure AD 安全组

由于通常会有多个开发人员处理一个应用程序,因此建议创建一个 Azure AD 组来封装应用在本地开发中所需的角色(权限),而不要将角色分配到单个服务主体对象。 这种做法的优势如下。

  • 由于角色是在组级别分配的,因此可以确保为每个开发人员分配相同的角色。
  • 如果应用需要新角色,只需将此角色添加到应用的 Azure AD 组即可。
  • 如果有新的开发人员加入团队,请为该开发人员创建一个新的应用程序服务主体并将其添加到该组中,以确保开发人员拥有正确的权限来处理应用。
说明 屏幕快照
在页面顶部的搜索框中键入“Azure Active Directory”,然后在服务下面选择“Azure Active Directory”,以导航到 Azure 门户中的“Azure Active Directory”页。 显示如何使用 Azure 门户顶部的搜索栏搜索并导航到“Azure Active Directory”页的屏幕截图。
在“Azure Active Directory”页上,从左侧菜单中选择“组”。 显示“组”菜单项在“Azure Active Directory 默认目录”页左侧菜单中的位置的屏幕截图。
在“所有组”页上,选择“新建组”。 显示“新建组”按钮在“所有组”页中的位置的屏幕截图。
在“新建组”页上
  1. 组类型 → 安全性
  2. 组名称 → 安全组的名称,通常是基于应用程序名称创建的。 在组的名称中包含类似于 local-dev 的字符串来指示组的用途也很有帮助。
  3. 组说明 → 组的用途说明。
  4. 在“成员”下选择“未选择成员”链接,以将成员添加到组中。
显示如何填写窗体,以便为应用程序创建新的 Azure Active Directory 组的屏幕截图。此屏幕截图还显示了用于将成员添加到此组的链接的位置
在“添加成员”对话框中
  1. 使用搜索框筛选列表中的主体名称。
  2. 为此应用选择用于本地开发的应用程序服务主体。 选择对象后,它们将会灰显并移至对话框底部的“选定项”列表中。
  3. 完成后,选择“选择”按钮。
“添加成员”对话框的屏幕截图,其中显示了如何选择要包含在组中的应用程序服务主体。
返回“新建组”页,选择“创建”以创建组。

随后会创建组,你将返回到“所有组”页。 最长可能需要在 30 秒后才会显示该组,由于 Azure 门户中会进行缓存,你可能需要刷新页面。
“新建组”页的屏幕截图,其中显示了如何选择“创建”按钮来完成该过程。

3 - 将角色分配到应用程序

接下来,需要确定应用在哪些资源上需要哪些角色(权限),并将这些角色分配到应用。 此示例将角色分配到在步骤 2 中创建的 Azure Active Directory 组。 可以在资源、资源组或订阅范围分配角色。 此示例演示如何在资源组范围分配角色,因为大多数应用程序将其所有 Azure 资源分组到单个资源组中。

说明 屏幕快照
使用 Azure 门户顶部的搜索框搜索资源组名称,找到应用程序的资源组。

在对话框中的“资源组”标题下选择资源组名称,导航到该资源组。
显示如何使用 Azure 门户中的顶部搜索框来查找并导航到要为其分配角色(权限)的资源组的屏幕截图。
在资源组的页面上,从左侧菜单中选择“访问控制(IAM)”。 资源组页面的屏幕截图,其中显示了“访问控制(IAM)”菜单项的位置。
在“访问控制(IAM)”页上
  1. 选择“角色分配”选项卡。
  2. 从顶部菜单中选择“+ 添加”,然后从出现的下拉菜单中选择“添加角色分配”。
显示如何导航到角色分配选项卡,以及用于将角色分配添加到资源组的按钮的位置的屏幕截图。
“添加角色分配”页列出了可为资源组分配的所有角色。
  1. 使用搜索框筛选列表,以便以更容易操作的大小显示内容。 此示例演示如何筛选存储 Blob 角色。
  2. 选择要分配的角色。
选择“下一步”转到下一屏幕。
显示如何筛选和选择要添加到资源组的角色分配的屏幕截图。
在下一个“添加角色分配”页面中,可以指定要将角色分配给哪个用户。
  1. 在“将访问权限分配给”下选择“用户、组或服务主体”。
  2. 在“成员”下选择“+ 选择成员”
Azure 门户的右侧将打开一个对话框。
显示用于将角色分配到 Azure AD 组的单选按钮,以及用于选择要将角色分配到的组的链接的屏幕截图。
在“选择成员”对话框中
  1. “选择”文本框可用于筛选订阅中的用户和组列表。 如果需要,请键入为应用创建的本地开发 Azure AD 组的前几个字符。
  2. 选择与应用程序关联的本地开发 Azure AD 组。
在对话框底部选择“选择”以继续。
显示如何在“选择成员”对话框中为应用程序筛选和选择 Azure AD 组的屏幕截图。
现在,该 Azure AD 组将在“添加角色分配”屏幕上显示为选中状态。

选择“查看 + 分配”转到最后一页,然后再次选择“查看 + 分配”完成该过程。
显示已完成的“添加角色分配”页,以及用于完成该过程的“查看 + 分配”按钮的位置的屏幕截图。

4 - 设置应用程序环境变量

在运行时,DefaultAzureCredential 对象将在一组环境变量中查找服务主体信息。 使用 .NET 时,可以根据你的工具和环境以多种方式配置环境变量。

无论选择哪种方法,在处理服务主体时都需要配置以下环境变量。

  • AZURE_CLIENT_ID → 应用 ID 值。
  • AZURE_TENANT_ID → 租户 ID 值。
  • AZURE_CLIENT_SECRET → 为应用生成的密码/凭据。

在本地使用 Visual Studio 时,可以在项目的 Properties 文件夹中的 launchsettings.json 文件内设置环境变量。 当应用启动时,会自动拉入这些值。 请记住,在部署时这些配置不会随应用程序一起移动,因此仍然需要在目标宿主环境中设置环境变量。

"profiles": {
    "SampleProject": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:7177;http://localhost:5177",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "AZURE_CLIENT_ID": "00000000-0000-0000-0000-000000000000",
        "AZURE_TENANT_ID":"11111111-1111-1111-1111-111111111111",
        "AZURE_CLIENT_SECRET": "=abcdefghijklmnopqrstuvwxyz"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "AZURE_CLIENT_ID": "00000000-0000-0000-0000-000000000000",
        "AZURE_TENANT_ID": "11111111-1111-1111-1111-111111111111",
        "AZURE_CLIENT_SECRET": "=abcdefghijklmnopqrstuvwxyz"
      }
    }
  }

5 - 在应用程序中实现 DefaultAzureCredential

DefaultAzureCredential 支持多种身份验证方法,并确定在运行时使用的身份验证方法。 这样,应用便可以在不同的环境中使用不同的身份验证方法,而无需实现特定于环境的代码。

DefaultAzureCredential 按哪种顺序和在哪个位置查找凭据见于 DefaultAzureCredential

若要实现 DefaultAzureCredential,首先请将 Azure.Identity 和可选的 Microsoft.Extensions.Azure 包添加到应用程序。 可以使用命令行或 NuGet 包管理器来执行此操作。

在应用程序项目目录中打开所选的终端环境,然后输入以下命令。

dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.Azure

通常会使用 SDK 中的相应客户端类来访问 Azure 服务。 应在 Program.cs 文件中注册这些类和你自己的自定义服务,以便可以在整个应用中通过依赖项注入来访问它们。 在 Program.cs 中,按照以下步骤正确设置服务和 DefaultAzureCredential

  1. 使用 using 指令包含 Azure.IdentityMicrosoft.Extensions.Azure 命名空间。
  2. 使用相关的帮助器方法注册 Azure 服务。
  3. DefaultAzureCredential 对象的实例传递给 UseCredential 方法。

以下代码片段中显示了此操作的示例。

using Microsoft.Extensions.Azure;
using Azure.Identity;

// Inside of Program.cs
builder.Services.AddAzureClients(x =>
{
    x.AddBlobServiceClient(new Uri("https://<account-name>.blob.core.windows.net"));
    x.UseCredential(new DefaultAzureCredential());
});

或者,也可以在服务中更直接地使用 DefaultAzureCredential,而无需借助其他 Azure 注册方法,如下所示。

using Azure.Identity;

// Inside of Program.cs
builder.Services.AddSingleton<BlobServiceClient>(x =>
    new BlobServiceClient(
        new Uri("https://<account-name>.blob.core.windows.net"),
        new DefaultAzureCredential()));

在本地开发期间,当上述代码在本地工作站上运行时,它将在环境变量中查找应用程序服务主体,或者在 Visual Studio、VS Code、Azure CLI 或 Azure PowerShell 中查找一组开发人员凭据,在本地开发期间,可以使用该服务主体或这些凭据对访问 Azure 资源的应用进行身份验证。

部署到 Azure 时,此代码也可以对访问 Azure 资源的应用进行身份验证。 DefaultAzureCredential 可以检索环境设置和托管标识配置,以自动向其他服务进行身份验证。