适用于 Java 的 Azure 标识客户端库中的凭据链

Azure 标识客户端库提供凭据—实现 Azure Core 库的 TokenCredential 接口的公共类。 凭据表示从 Microsoft Entra ID 获取访问令牌的独特身份验证流。 这些凭证可以链接在一起,形成要尝试的身份验证机制的有序序列。

链接凭据的工作原理

在运行时,凭证链尝试使用序列的第一个凭据进行身份验证。 如果该凭据无法获取访问令牌,则会尝试序列中的下一个凭据,以此类推,直到成功获取访问令牌。 以下序列图说明了这种行为:

显示凭据链序列的示意图。

为何使用凭据链

链接凭据可提供以下优势:

  • 环境感知:根据应用运行的环境自动选择最合适的凭据。 如果没有它,必须编写如下所示的代码:

    import com.azure.core.credential.TokenCredential;
    import com.azure.identity.AzureCliCredentialBuilder;
    import com.azure.identity.ManagedIdentityCredentialBuilder;
    
    // Code omitted for brevity
    
    TokenCredential credential = null;
    
    // Set up credential based on environment (Azure or local development)
    String environment = System.getenv("ENV");
    
    if (environment != null && environment.equals("production")) {
        credential = new ManagedIdentityCredentialBuilder()
            .clientId(userAssignedClientId)
            .build();
    } else {
        credential = new AzureCliCredentialBuilder()
            .build();
    }
    
  • 无缝转换:应用可以在不更改身份验证代码的情况下从本地开发迁移到暂存或生产环境。

  • 改进了复原能力:包括一个回退机制,当前一个凭据无法获取访问令牌时,该机制会移动到下一个凭据。

如何选择链接凭据

凭据链接有两种不同的理念:

  • 使用预配置链:从符合最常见身份验证方案的固执、预先构造的链开始。 有关此方法,请参阅 DefaultAzureCredential 概述部分。
  • “构建”链:从空链开始,仅包含所需的内容。 有关此方法,请参阅 ChainedTokenCredential 概述部分。

DefaultAzureCredential 概述

DefaultAzureCredential 是一个固定的预配置凭据链。 它旨在支持许多环境,以及最常见的身份验证流和开发人员工具。 在图形形式中,基础链如下所示:

显示 DefaultAzureCredential 身份验证流的示意图。

DefaultAzureCredential 尝试凭据的顺序如下。

订单 凭据 说明
1 环境 读取环境变量集合,以确定是否为应用配置了应用程序服务主体(应用程序用户)。 如果是,则 DefaultAzureCredential 将使用这些值对访问 Azure 的应用进行身份验证。 此方法最常用于服务器环境,但也可以在进行本地开发时使用。
2 工作负载标识 如果将应用部署到启用了工作负载标识的 Azure 主机,请对该帐户进行身份验证。
3 托管标识 如果应用部署到启用了托管标识的 Azure 主机,请使用该托管标识向 Azure 验证应用。
4 共享令牌缓存 如果开发人员通过登录到 Visual Studio 向 Azure 进行身份验证,请使用同一帐户向 Azure 验证应用。 (仅限 Windows。)
5 IntelliJ 如果开发人员已通过 Azure Toolkit for IntelliJ 进行身份验证,请对该帐户进行身份验证。
6 Azure CLI 如果开发人员使用 Azure CLI az login 的命令向 Azure 进行身份验证,请使用同一帐户向 Azure 验证应用。
7 Azure PowerShell 如果开发人员使用 Azure PowerShell Connect-AzAccount cmdlet 向 Azure 进行身份验证,请使用同一帐户向 Azure 验证应用。
8 Azure 开发人员 CLI 如果开发人员使用 Azure Developer CLI 的 azd auth login 命令向 Azure 进行身份验证,请使用该帐户进行身份验证。

最简单的形式是,可以使用 DefaultAzureCredential 的无参数版本,如下所示:

import com.azure.identity.DefaultAzureCredential;
import com.azure.identity.DefaultAzureCredentialBuilder;

// Code omitted for brevity

DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
    .build();

ChainedTokenCredential 概述

ChainedTokenCredential 是一个空链,可向其添加凭据以满足应用的需求。 例如:

import com.azure.identity.AzureCliCredential;
import com.azure.identity.AzureCliCredentialBuilder;
import com.azure.identity.ChainedTokenCredential;
import com.azure.identity.ChainedTokenCredentialBuilder;
import com.azure.identity.ManagedIdentityCredential;
import com.azure.identity.ManagedIdentityCredentialBuilder;

// Code omitted for brevity

ManagedIdentityCredential miCredential = new ManagedIdentityCredentialBuilder()
    .clientId(userAssignedClientId)
    .build();
AzureCliCredential cliCredential = new AzureCliCredentialBuilder()
    .build();

ChainedTokenCredential credential = new ChainedTokenCredentialBuilder()
    .addLast(miCredential)
    .addLast(cliCredential)
    .build();

前面的代码示例创建了一个由两个凭据组成的定制凭据链。 首先尝试 ManagedIdentityCredential 的用户分配的托管标识变体,然后在必要时尝试 AzureCliCredential。 在图形形式中,链如下所示:

显示由托管标识凭据和 Azure CLI 凭据组成的 ChainedTokenCredential 实例的身份验证流的示意图。

提示

为了提高性能,请在 ChainedTokenCredential 中为生产环境优化凭据排序。 应最后添加用于本地开发环境的凭据。

DefaultAzureCredential 的使用指南

DefaultAzureCredential 无疑是开始使用 Azure 标识客户端库的最简单方法,但随之而来的是权衡。 将应用部署到 Azure 后,应了解应用的身份验证要求。 因此,强烈建议从 DefaultAzureCredential 迁移到以下解决方案之一:

  • 特定的凭据实现,例如 ManagedIdentityCredential
  • 针对运行应用的 Azure 环境优化的精简版 ChainedTokenCredential 实现。

原因如下:

  • 调试挑战:身份验证失败时,调试和识别违规凭据可能很困难。 必须启用日志记录,才能查看从一个凭据到下一个凭据的进度以及每个凭据的成功/失败状态。 有关详细信息,请参阅调试链接凭据
  • 性能开销:按顺序尝试多个凭据的过程可能会导致性能开销。 例如,在本地开发计算机上运行时,托管标识不可用。 因此,ManagedIdentityCredential 在本地开发环境中始终失败。
  • 不可预知的行为DefaultAzureCredential检查是否存在某些环境变量。 有可能有人可以在主机上的系统级别添加或修改这些环境变量。 这些更改在全局范围内适用,因此会在该计算机上运行的任何应用中改变 DefaultAzureCredential 在运行时的行为。

调试链接凭据

若要诊断意外问题或了解链接凭据正在执行的操作,请在应用中启用日志记录

为了便于说明,假设使用 DefaultAzureCredential 的无参数形式对 Blob 存储帐户的请求进行身份验证。 应用在本地开发环境中运行,开发人员使用 Azure CLI 向 Azure 进行身份验证。 运行应用程序时,输出中会出现以下相关条目:

[main] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential EnvironmentCredential is unavailable.
[main] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential WorkloadIdentityCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] WARN com.microsoft.aad.msal4j.ConfidentialClientApplication - [Correlation ID: aaaa0000-bb11-2222-33cc-444444dddddd] Execution of class com.microsoft.aad.msal4j.AcquireTokenByClientCredentialSupplier failed: java.util.concurrent.ExecutionException: com.azure.identity.CredentialUnavailableException: ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established.
[main] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential ManagedIdentityCredential is unavailable.
[main] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential SharedTokenCacheCredential is unavailable.
[main] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential IntelliJCredential is unavailable.
[main] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential AzureCliCredential returns a token

在前面的输出中,请注意:

  • EnvironmentCredentialWorkloadIdentityCredentialManagedIdentityCredentialSharedTokenCacheCredentialIntelliJCredential 都未能按该顺序获取 Microsoft Entra 访问令牌。
  • 调用 AzureCliCredential.getToken 成功,由 returns a token 后缀条目指示。 由于 AzureCliCredential 成功,因此未尝试超出它的凭据。