使用服务主体在本地开发期间向 Azure 服务验证 JavaScript 应用的身份
创建云应用程序时,开发人员需要在其本地工作站上调试和测试应用程序。 在本地开发期间,当应用程序在开发人员的工作站上运行时,它仍然必须向应用使用的任何 Azure 服务进行身份验证。 本文介绍如何设置要在本地开发期间使用的专用应用程序服务主体对象。
使用用于本地开发的专用应用程序服务主体可以在应用开发期间遵循最低特权原则。 由于权限的范围严格限定为开发期间应用所需的权限,因此可以防止应用代码意外访问仅供其他应用使用的 Azure 资源。 此方法还可防止在将应用移动到生产环境时发生 bug,因为该应用在开发环境中过度使用。
在 Azure 中注册应用时,将为该应用设置应用程序服务主体。 为本地开发注册应用时,建议:
- 为每个处理该应用的开发人员单独创建应用注册。 此方法为每个开发人员创建单独的应用程序服务主体,以便在本地开发期间使用,并避免开发人员需要为单个应用程序服务主体共享凭据。
- 为每个应用单独创建应用注册。 这会将应用的权限范围限定为该应用所需的权限。
在本地开发期间,将使用应用程序服务主体的标识设置环境变量。 用于 JavaScript 的 Azure SDK 读取这些环境变量,并使用此信息向所需的 Azure 资源对应用进行身份验证。
1 - 在 Azure 中注册应用程序
应用程序服务主体对象是使用 Azure 中的应用注册创建的。 可以使用 Azure 门户 或 Azure CLI 创建服务主体。
登录到 Azure 门户并执行以下步骤。
2 - 创建用于本地开发的 Microsoft Entra 安全组
由于通常有多个开发人员在应用程序中工作,因此建议创建一个Microsoft Entra 组来封装应用在本地开发中所需的角色(权限),而不是将角色分配给单个服务主体对象。 这种做法的优势如下。
- 由于角色是在组级别分配的,因此可以确保为每个开发人员分配相同的角色。
- 如果应用需要新角色,则只需将其添加到应用的 Microsoft Entra 组即可。
- 如果有新的开发人员加入团队,请为该开发人员创建一个新的应用程序服务主体并将其添加到该组中,以确保开发人员拥有正确的权限来处理应用。
3 - 将角色分配到应用程序
接下来,需要确定应用在哪些资源上需要哪些角色(权限),并将这些角色分配到应用。 在此示例中,角色将分配给在步骤 2 中创建的 Microsoft Entra 组。 可以在资源、资源组或订阅范围分配角色。 此示例演示如何在资源组范围分配角色,因为大多数应用程序将其所有 Azure 资源分组到单个资源组中。
4 - 设置本地开发环境环境
该 DefaultAzureCredential
对象在运行时查找一组环境变量中的服务主体信息。 由于大多数开发人员处理多个应用程序,因此建议使用类似于 dotenv 的包从.env
开发期间存储在应用程序目录中的文件访问环境。 这会限定用于向 Azure 对应用程序进行身份验证的环境变量的范围,以便它们只能由此应用程序使用。
从未将 .env
文件签入源控制,因为它包含 Azure 的应用程序密钥。 JavaScript 的标准 .gitignore 文件会自动从签入中排除 .env
该文件。
若要使用该 dotenv
包,请先在应用程序中安装该包。
npm install dotenv
然后,在应用程序根目录中创建 .env
文件。 如下所示,使用从应用注册进程获取的值设置环境变量值:
AZURE_CLIENT_ID
→ 应用 ID 值。AZURE_TENANT_ID
→ 租户 ID 值。AZURE_CLIENT_SECRET
→ 为应用生成的密码/凭据。
AZURE_CLIENT_ID=00001111-aaaa-2222-bbbb-3333cccc4444
AZURE_TENANT_ID=ffffaaaa-5555-bbbb-6666-cccc7777dddd
AZURE_CLIENT_SECRET=Aa1Bb~2Cc3.-Dd4Ee5Ff6Gg7Hh8Ii9_Jj0Kk1Ll2
最后,在应用程序的启动代码中,使用 dotenv
库在启动时从 .env
文件中读取环境变量。
import 'dotenv/config'
5 - 在应用程序中实现 DefaultAzureCredential
若要向 Azure 对 Azure SDK 客户端对象进行身份验证,应用程序应使用 @azure/identity
包中的 DefaultAzureCredential
类。 在此方案中, DefaultAzureCredential
检测环境变量 AZURE_CLIENT_ID
, AZURE_TENANT_ID
并 AZURE_CLIENT_SECRET
设置并读取这些变量,以获取连接到 Azure 的应用程序服务主体信息。
首先将 @azure/标识 包添加到应用程序。
npm install @azure/identity
接下来,对于在应用中创建 Azure SDK 客户端对象的任何 JavaScript 代码,你需要:
- 从
@azure/identity
模块中导入DefaultAzureCredential
类。 - 创建
DefaultAzureCredential
对象。 - 将
DefaultAzureCredential
对象传递给 Azure SDK 客户端对象构造函数。
以下代码片段中显示了此操作的示例。
// Azure authentication dependency
import { DefaultAzureCredential } from '@azure/identity';
// Azure resource management dependency
import { SubscriptionClient } from "@azure/arm-subscriptions";
// Acquire credential
const tokenCredential = new DefaultAzureCredential();
async function listSubscriptions() {
try {
// use credential to authenticate with Azure SDKs
const client = new SubscriptionClient(tokenCredential);
// get details of each subscription
for await (const item of client.subscriptions.list()) {
const subscriptionDetails = await client.subscriptions.get(
item.subscriptionId
);
/*
Each item looks like:
{
id: '/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e',
subscriptionId: 'aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e',
displayName: 'YOUR-SUBSCRIPTION-NAME',
state: 'Enabled',
subscriptionPolicies: {
locationPlacementId: 'Internal_2014-09-01',
quotaId: 'Internal_2014-09-01',
spendingLimit: 'Off'
},
authorizationSource: 'RoleBased'
},
*/
console.log(subscriptionDetails);
}
} catch (err) {
console.error(JSON.stringify(err));
}
}
listSubscriptions()
.then(() => {
console.log("done");
})
.catch((ex) => {
console.log(ex);
});
DefaultAzureCredential
将自动检测为应用配置的身份验证机制,并获取必要的令牌,以便向 Azure 对应用进行身份验证。 如果应用程序使用多个 SDK 客户端,则同一凭据对象可与每个 SDK 客户端对象一起使用。