从本地托管的 .NET 应用向 Azure 资源进行身份验证

在 Azure 外部(例如本地或第三方数据中心)托管的应用在访问 Azure 资源时应使用应用程序服务主体向 Azure 进行身份验证。 应用程序服务主体对象是使用 Azure 中的应用注册过程创建的。 创建应用程序服务主体时,将为应用生成客户端 ID 和客户端机密。 然后客户端 ID、客户端机密和租户 ID 将存储在环境变量中,以便在运行时 Azure SDK for .NET 可以使用它们来对访问 Azure 的应用进行身份验证。

应为托管应用的每个环境创建不同的应用注册。 这样,就可以为每个服务主体配置特定于环境的资源权限,并确保部署到一个环境的应用不会与另一个环境中的 Azure 资源通信。

1 - 在 Azure 中注册应用程序

可以使用 Azure 门户或 Azure CLI 向 Azure 注册应用。

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

说明 屏幕快照
在 Azure 门户中:
  1. 在 Azure 门户顶部的搜索栏中输入“应用注册”。
  2. 在搜索栏下方显示的菜单中的“服务”标题下,选择标有“应用注册”的项。
A screenshot showing how to use the top search bar in the Azure portal to find and navigate to the App registrations page.
在“应用注册”页上,选择“+ 新建注册”。 A screenshot showing the location of the New registration button in the App registrations page.
在“注册应用程序”页上,按如下所示填写窗体。
  1. 名称 → 输入该应用注册在 Azure 中的名称。 建议在此名称中包含应用名称和应用注册所针对的环境(测试、生产)。
  2. 支持的帐户类型 → 仅限此组织目录中的帐户。
选择“注册”以注册应用并创建应用程序服务主体。
A screenshot showing how to fill out the Register an application page by giving the app a name and specifying supported account types as accounts in this organizational directory only.
在应用的“应用注册”页上:
  1. 应用程序(客户端) ID → 这是在本地开发期间由应用用来访问 Azure 的应用 ID。 将此值复制到文本编辑器中的临时位置,因为在稍后的步骤中需要用到。
  2. 目录(租户) ID → 应用在向 Azure 进行身份验证时也需要此值。 将此值复制到文本编辑器中的临时位置,因为在稍后的步骤中也需要用到。
  3. 客户端凭据 → 必须先为应用设置客户端凭据,然后应用才能向 Azure 进行身份验证并使用 Azure 服务。 选择“添加证书或机密”以添加应用的凭据。
A screenshot of the App registration page after the app registration has been completed. This screenshot shows the location of the application ID and tenant ID which will be needed in a future step. It also shows the location of the link to use to add an application secret for the app.
在“证书和机密”页上,选择“+ 新建客户端密码”。 A screenshot showing the location of the link to use to create a new client secret on the certificates and secrets page.
页面右侧会弹出“添加客户端机密”对话框。 在此对话框中:
  1. 说明 → 输入值“当前”。
  2. 过期时间 → 选择值“24 个月”。
选择“添加”以添加机密。

重要说明:在日历中设置机密过期日期之前发出的提醒。这样,可以在此机密过期之前添加新机密和更新应用,并避免应用中出现服务中断。
A screenshot showing the page where a new client secret is added for the application service principal created by the app registration process.
在“证书和机密”页上,你将看到客户端密码的值。

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

重要说明:此值只会显示一次。一旦你离开或刷新此页,将不再可以看到此值。 可以在不使此客户端机密失效的情况下添加一个额外的客户端机密,但不再可以看到此值。
A screenshot showing the page with the generated client secret.

2 - 将角色分配到应用程序服务主体

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

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

在对话框中的“资源组”标题下选择资源组名称,导航到该资源组。
A screenshot showing how to use the top search box in the Azure portal to locate and navigate to the resource group you want to assign roles (permissions) to.
在资源组的页面上,从左侧菜单中选择“访问控制(IAM)”。 A screenshot of the resource group page showing the location of the Access control (IAM) menu item.
在“访问控制(IAM)”页上
  1. 选择“角色分配”选项卡。
  2. 从顶部菜单中选择“+ 添加”,然后从出现的下拉菜单中选择“添加角色分配”。
A screenshot showing how to navigate to the role assignments tab and the location of the button used to add role assignments to a resource group.
“添加角色分配”页列出了可为资源组分配的所有角色。
  1. 使用搜索框筛选列表,以便以更容易操作的大小显示内容。 此示例演示如何筛选存储 Blob 角色。
  2. 选择要分配的角色。
选择“下一步”转到下一屏幕。
A screenshot showing how to filter and select role assignments to be added to the resource group.
在下一个“添加角色分配”页面中,可以指定要将角色分配给哪个用户。
  1. 在“将访问权限分配给”下选择“用户、组或服务主体”。
  2. 在“成员”下选择“+ 选择成员”
Azure 门户的右侧将打开一个对话框。
A screenshot showing the radio button to select to assign a role to an Azure AD group and the link used to select the group to assign the role to.
在“选择成员”对话框中
  1. “选择”文本框可用于筛选订阅中的用户和组列表。 如果需要,请键入为应用创建的服务主体的前几个字符以筛选列表。
  2. 选择与应用程序关联的服务主体。
在对话框底部选择“选择”以继续。
A screenshot showing how to filter for and select the Azure AD group for the application in the Select members dialog box.
现在,该服务主体将在“添加角色分配”屏幕上显示为选中状态。

选择“查看 + 分配”转到最后一页,然后再次选择“查看 + 分配”完成该过程。
A screenshot showing the completed Add role assignment page and the location of the Review + assign button used to complete the process.

3 - 为应用程序配置环境变量

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

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

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

如果应用托管在 IIS 中,建议为每个应用池设置环境变量,以隔离应用程序之间的设置。

appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='Contoso'].environmentVariables.[name='ASPNETCORE_ENVIRONMENT',value='Production']" /commit:apphost
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='Contoso'].environmentVariables.[name='AZURE_CLIENT_ID',value='00000000-0000-0000-0000-000000000000']" /commit:apphost
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='Contoso'].environmentVariables.[name='AZURE_TENANT_ID',value='11111111-1111-1111-1111-111111111111']" /commit:apphost
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='Contoso'].environmentVariables.[name='AZURE_CLIENT_SECRET',value='=abcdefghijklmnopqrstuvwxyz']" /commit:apphost

还可以在 applicationHost.config 文件中使用 applicationPools 元素直接配置这些设置。

<applicationPools>
   <add name="CorePool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic">
      <environmentVariables>
         <add name="ASPNETCORE_ENVIRONMENT" value="Development" />
         <add name="AZURE_CLIENT_ID" value="00000000-0000-0000-0000-000000000000" />
         <add name="AZURE_TENANT_ID" value="11111111-1111-1111-1111-111111111111" />
         <add name="AZURE_CLIENT_SECRET" value="=abcdefghijklmnopqrstuvwxyz" />
      </environmentVariables>
   </add>
</applicationPools>

4 - 在应用程序中实现 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 可以检索环境设置和托管标识配置,以自动向其他服务进行身份验证。