使用联合标识凭据实现身份验证

适用于: SDK v4

注意

目前,这只适用于 Microsoft 租户。

有关 Bot Framework 如何处理此类身份验证的概述,请参阅用户身份验证

本文介绍了如何:

  • 创建 Azure 机器人资源。
  • 创建 Microsoft Entra ID 标识提供者并使用联合凭据流。
  • 在机器人上注册 Microsoft Entra ID 标识提供者,以便使用联合凭据流进行用户身份验证。
  • 准备机器人代码。

完成这篇文章后,你就拥有了一个可以响应一些简单任务的机器人。

注意

Bot Framework JavaScript、C# 和 Python SDK 将继续受支持,但 Java SDK 即将停用,最终长期支持将于 2023 年 11 月结束。

使用 Java SDK 构建的现有机器人将继续正常运行。

要生成新的机器人,请考虑使用 Microsoft Copilot Studio 并阅读选择正确的助理解决方案

有关详细信息,请参阅机器人构建的未来

先决条件

  • 了解机器人基础知识管理状态对话库、如何实现顺序聊天流,以及如何重复使用对话

  • 具备 Azure 和 OAuth 2.0 开发方面的知识。

  • 适用于 .NET 的 Visual Studio 2017 或更高版本。

  • 适用于 JavaScript 的 Node.js。

  • 适用于 Python 的 Python 3.8+

  • 所列示例之一。

    示例 BotBuilder 版本 演示
    C# 中的身份验证 v4 OAuthCard 支持

    若要运行本文中引用的示例,你需要:

    • Microsoft Entra ID 应用程序,用于在 Azure 中注册机器人资源。 此应用程序允许机器人访问受保护的外部资源,如 Microsoft Graph。 它还允许用户通过多个频道(如 Web Chat)与机器人通信。
    • 作为标识提供者的单独 Microsoft Entra ID 应用程序。 此应用程序提供在机器人与受保护资源之间建立 OAuth 连接所需的凭据。 请注意,本文使用 Active Directory 作为标识提供者。 另外还支持许多其他的提供者。

重要

每当你在 Azure 中注册机器人时,系统都会为它分配一个 Microsoft Entra ID 应用程序。 但是,此应用程序可确保从通道到机器人的访问的安全性。 对于每个受保护的外部资源,如果希望机器人代表用户对其进行访问,则需要一个额外的 Microsoft Entra ID 应用程序。

创建 Azure 机器人资源

创建 Azure 机器人资源,你可以通过该资源向 Azure AI 机器人服务注册自己的机器人。

提示

无法创建新的 Web 应用机器人机器人通道注册资源;但是,已配置和部署的任何此类现有资源将继续有效。 使用(从 SDK 版本 4.14.1.2 或更高版本创建的)VSIX 或 Yeoman 模板创建的机器人包含将生成 Azure 机器人资源的 ARM 模板。

  1. 转到 Azure 门户

  2. 在右窗格中,选择“创建资源”。

  3. 在搜索框中,键入 bot,然后按 Enter

  4. 选择 Azure 机器人卡。

    选择 Azure 机器人资源

  5. 选择创建

  6. 在必填字段中输入值,并检查和更新设置。

    1. 在“项目详细信息”下提供信息。 选择机器人是使用全局数据驻留还是本地数据驻留。 有关详细信息,请参阅 Azure AI 机器人服务中的区域化

      Azure 机器人资源的项目详细信息设置

    2. 在“Microsoft 应用 ID”下提供信息。 选择在 Azure 中管理机器人标识的方式,以及是创建新标识还是使用现有标识。

      Azure 机器人资源的 Microsoft 应用 ID 设置

  7. 选择“查看 + 创建”。

  8. 验证通过后,选择“创建”。

  9. 部署完成后,请选择“转到资源”。 应会看到所选资源组中列出的机器人和相关资源。

  10. 如果还没有 Bot Framework SDK,请选择“从 GitHub 下载”,了解如何使用首选语言的包。

    在 SDK 中创建机器人

现在,你已经准备好使用 Bot Framework SDK 生成机器人。

创建用户分配的托管标识

创建用户分配的托管标识资源,该资源允许设置一个标识,以用作从 Microsoft Entra 应用程序获取访问令牌的信任机制。

  1. 转到 Azure 门户

  2. 在右窗格中,选择“创建资源”。

  3. 在搜索框中,键入 Managed Identities,然后按 Enter

  4. 选择“用户分配的托管标识”卡片。

    选择“用户分配的托管标识”

  5. 选择创建

  6. 在必填字段中输入值,并检查和更新设置。

    1. 在“项目详细信息”下提供信息。 选择标识是使用全局数据驻留还是本地数据驻留。

      托管标识的项目详细信息设置

  7. 选择“查看 + 创建”。

  8. 验证通过后,选择“创建”。

  9. 部署完成后,请选择“转到资源”。 你应该能看到所选资源组中列出的托管标识和相关资源。

创建新的联合凭据

机器人应用程序服务资源的所有者可以添加新的信任:

  1. 转到机器人的“Azure 机器人”资源边栏选项卡。

  2. 转到机器人的“配置”边栏选项卡。

  3. 选择 Microsoft 应用 ID 旁边的管理,转到应用程序服务的证书 + 机密边栏选项卡。

  4. 在“证书 + 机密”边栏选项卡上,选择“联合凭据”选项卡和“添加凭据 (+)”。

    创建联合凭据。

  5. 在“添加凭据”页上,在“联合凭据方案”中选择为“客户管理的密钥”

    选择“联合凭据方案”。

  6. 在必填字段中输入值,并检查和更新设置

    1. 在“选择托管标识”下提供信息。 选择“托管标识”部分
      1. 在“选择托管标识”边栏选项卡上:
      2. 选择订阅。
      3. 对于“用户分配的托管标识”,选择之前创建的托管标识。
      4. 选择“选择”以便将此标识用于你的机器人。 选择托管标识
    2. 在“凭据详细信息”下提供信息。 输入凭据详细信息
  7. 选择“添加”以添加凭据。

更新机器人

注意

Bot Framework SDK 4.22.8 或更高版本支持使用联合凭据。

  1. 将 Bot Framework SDK 升级到 4.22.8 或更高版本。

  2. 要为机器人启用联合凭据,请在 Startup.cs 文件中添加以下代码:

    services.AddSingleton<ServiceClientCredentialsFactory>(new FederatedServiceClientCredentialsFactory(
        Configuration["MicrosoftAppId"],
        Configuration["MicrosoftAppClientId"],
        Configuration["MicrosoftAppTenantId"]));
    
  3. 按照以下步骤在机器人的配置文件中加入标识信息。 具体的文件和步骤可能会因创建机器人所使用的编程语言而有所不同。

    重要

    Bot Framework SDK 的 Java 版本仅支持多租户机器人。 C#、JavaScript 和 Python 版本支持用于管理机器人标识的所有三种应用程序类型。

    语言 文件名 备注
    C# appsettings.json 支持所有三种应用程序类型来管理机器人的标识。
    JavaScript .env 支持所有三种应用程序类型来管理机器人的标识。
    Java application.properties 仅支持多租户机器人。
    Python config.py 支持所有三种应用程序类型来管理机器人的标识。

需要添加的标识信息取决于机器人的应用程序类型。 提供配置文件中的以下值。

属性
MicrosoftAppType SingleTenant/MultiTenant
MicrosoftAppId 机器人的应用 ID。
MicrosoftAppClientId 用户托管标识密码。
MicrosoftAppTenantId 机器人的应用租户 ID。

若要获取应用或租户 ID

若要获取机器人的应用或租户 ID:

  1. 转到机器人的“Azure 机器人”资源边栏选项卡。
  2. 转到机器人的“配置”边栏选项卡。 在此边栏选项卡中,可以复制机器人的“Microsoft 应用 ID”或“应用租户 ID”。

若要更新应用程序服务

如果机器人使用现有的应用程序服务资源(Web 应用),并且是单租户多租户应用程序,则可能需要更新其应用程序服务。

  1. 转到机器人 Web 应用的“应用程序服务”边栏选项卡。
  2. 在“设置”下选择“标识”。
  3. 在“标识”边栏选项卡上,选择“用户分配”选项卡和“添加”(+)。
  4. 在“添加用户分配的托管标识”边栏选项卡上:
    1. 选择订阅。

    2. 对于“用户分配的托管标识”,选择之前创建的托管标识。

    3. 选择“添加”以将此标识用于机器人。

      “应用程序服务标识”边栏选项卡,其中选择了机器人的托管标识。

Microsoft Entra ID 标识服务

Azure AD 是一个云标识服务,你可以通过它生成应用程序,以便使用 OAuth 2.0 之类的行业标准协议安全地登录用户。

可以使用以下两个标识服务之一:

  1. Microsoft Entra ID 开发人员平台 (v1.0)。 也称 Azure AD v1 终结点,用于生成应用,方便用户使用 Microsoft 工作或学校帐户安全地登录。 有关详细信息,请查看面向开发人员的 Microsoft Entra ID (v1.0) 概述

  2. Microsoft 标识平台 (v2.0)。 也称为 Microsoft Entra ID 终结点,它是 Azure AD 平台 (v1.0) 的进化版。它允许生成可登录到所有 Microsoft 标识提供者的应用程序,并获取调用 Microsoft API(如 Microsoft Graph)或其他开发人员生成的 API 的令牌。 有关详细信息,请参阅 Microsoft 标识平台 (v2.0) 概述

有关完整信息,请参阅 Microsoft 标识平台(旧称针对开发人员的 Microsoft Entra ID)

创建 Microsoft Entra ID 标识提供者

本部分介绍如何创建使用 OAuth 2.0 对机器人进行身份验证的 Microsoft Entra ID 身份提供程序。 可以使用 Azure AD v1 或 Microsoft Entra ID 终结点。

提示

你需要在租户中创建和注册 Microsoft Entra ID 应用程序,在租户中你可以同意应用程序请求的委托权限。

  1. 在 Azure 门户中打开 Microsoft Entra ID 面板。 如果进入了错误的租户,请选择“切换目录”切换到正确的租户。 (有关创建租户方法的信息,请参阅访问门户并创建租户。)

  2. 打开“应用注册”面板。

  3. 在“应用注册”面板中,选择“新建注册”

  4. 填写必填字段并创建应用注册。

    1. 为应用程序命名。

    2. 为应用程序选择“支持的帐户类型”。 (这些选项中的任何一个都适用于本示例。)

    3. 对于“重定向 URI”,请选择 Web,并将 URL 设置为受支持的 OAuth 重定向 URL 之一。

    4. 选择“注册”。

      • 在创建后,Azure 会显示应用的“概述”页。
      • 记录“应用程序(客户端) ID”值。 稍后,在创建连接字符串并在机器人注册时注册 Microsoft Entra ID 提供程序时,可以将此值用作客户端 ID
      • 记录“目录(租户) ID”值。 可以使用此值在机器人中注册该提供程序。
  5. 在导航窗格中选择“证书 & 机密”,为应用程序创建机密。

    1. 在“联合凭据”下,选择“添加凭据”

      创建联合凭据。

    2. 在“添加凭据”页中,为“联合凭据方案”选择“其他颁发者”

      选择联合凭据其他颁发者方案。

    3. 在必填字段中输入值,并检查和更新设置

      1. 在“连接你的帐户”下提供信息。

        连接到帐户

        1. 颁发者https://login.partner.microsoftonline.cn/{customer-tenant-ID}/oauth2/v2.0/token

        2. 使用者标识符:/eid1/c/pub/t/{base64 encoded customer tenant ID}/a/{base64 encoded 1-P app client ID}/{unique-identifier-for-projected-identity}

          • 下表包含支持的第一方应用程序 ID 的 Base64url 编码字节数组表示形式。 使用此值表示我们的第一方应用。

            编码值 说明
            9ExAW52n_ky4ZiS_jhpJIQ 机器人服务令牌存储的 Base64url 编码
            ND1y8_Vv60yhSNmdzSUR_A Bot Framework 开发门户的 Base64url 编码
          • 下表包含一些受支持租户 ID 的 Base64url 编码字节数组表示形式。 使用代表应用租户的值。 生成 base64url 编码字节数组的示例代码见 [https://dotnetfiddle.net/dpTlF6]。

            编码值 说明
            v4j5cvGGr0GRqy180BHbRw Base64url 编码的 MSIT 租户 ID (72f988bf-86f1-41af-91ab-2d7cd011db47)
            PwFflyR_6Een06vEdSvzRg Base64url 编码的 PME 租户 ID (975f013f-7f24-47e8-a7d3-abc4752bf346)
            6q7FzcUVtk2wefyt0lBdwg Base64url 编码的 Torus 租户 ID (cdc5aeea-15c5-4db6-b079-fcadd2505dc2)
            IRngM2RNjE-gVVva_9XjPQ Base64url 编码的 AME 租户 ID (33e01921-4d64-4f8c-a055-5bdaffd5e33d)

          主标识服务所有者只需计算一次,然后将其提供给使用者。

        3. 受众:api://AzureADTokenExchange

        4. unique-identifier-for-projected-identity:令牌的值与向 1-P 应用程序请求令牌以在客户租户中模拟时使用的值相同,在请求属性 - fmi_path 中作为客户参数传递。

      2. 在“凭据详细信息”下提供信息。

        输入凭据详细信息

      3. 选择“添加”以添加凭据。

  6. 在导航窗格中,选择“API 权限”打开“API 权限”面板。 最佳做法是为应用显式设置 API 权限。

    1. 选择“添加权限”,显示“请求 API 权限”窗格。

    2. 对于此示例,请选择“Microsoft API”和“Microsoft Graph”。

    3. 选择“委托的权限”,确保选中所需权限。 本示例需要这些权限。

      注意

      标记为“需要管理员同意”的任何权限都需要用户和租户管理员登录,因此对于机器人来说,请尽量避免这些操作

      • openid
      • profile
      • Mail.Read
      • Mail.Send
      • User.Read
      • User.ReadBasic.All
    4. 选择“添加权限”。 (用户首次通过机器人访问此应用时需要征得同意。)

现在就已经配置了 Microsoft Entra ID 应用程序。

注意

在创建连接字符串和使用机器人注册注册标识提供者时,你将分配应用程序(客户端)ID。 请参阅下一节。

使用机器人注册 Microsoft Entra ID 标识提供者

下一步是向机器人注册标识提供者。

Microsoft Entra ID

  1. Azure 门户中,打开机器人的“Azure 机器人”资源页。

  2. 选择“设置”。

  3. 在页面底部附近的“OAuth 连接设置”下,选择“添加设置”

  4. 按如下所示填写表单:

    1. Name。 输入连接的名称。 你可以在机器人代码中使用它。

    2. 服务提供商。 选择“包含联合凭据的 AAD v2”,以显示特定于 Microsoft Entra ID 的字段。

    3. “客户端 ID”。输入为 Microsoft Entra ID 标识提供者记录的应用程序(客户端)ID。

    4. 唯一标识符。 输入在创建联合凭据时为 Microsoft Entra ID 标识提供者记录的唯一标识符。

    5. 令牌交换 URL。 将它留空,因为它仅用于 Microsoft Entra ID 中的 SSO。

    6. 租户 ID。 请输入此前为 Microsoft Entra ID 应用记录的“目录(租户)ID”,或者输入 common,具体取决于在创建 Azure DD 应用时所选的受支持帐户的类型。 若要确定要分配的值,请遵循以下条件:

      • 如果已选择“仅在此组织目录中的帐户 (仅 Microsoft - 单一租户)”,请在创建 Microsoft Entra ID 应用时,输入此前为 Microsoft Entra ID 应用记录的租户 ID。
      • 但是,如果选择了“任何组织目录中的帐户 (任何 Microsoft Entra ID 目录 - 多租户和个人 Microsoft 帐户,例如 Xbox、Outlook.com)”或“任何组织目录中的帐户 (Microsoft Entra ID 目录 - 多租户)”,请输入 common 而不是租户 ID。 否则,Microsoft Entra ID 应用程序会通过选择 ID 的租户进行验证,并排除个人 Microsoft 帐户。

      这是与可进行身份验证的用户相关联的租户。 有关详细信息,请参阅 Microsoft Entra ID 中的租户

    7. 对于“范围”,输入从应用程序注册中选择的权限的名称。 对于测试,可只输入:openid profile

      注意

      对于 Microsoft Entra ID,“范围”字段的值区分大小写,以空格分隔

  5. 选择“保存”。


测试你的连接

  1. 选择连接项打开创建的连接。
  2. 选择“服务提供方连接设置”窗格顶部的“测试连接”。
  3. 第一次进行此操作时,应该会打开一个新的浏览器选项卡(其中列出了应用请求的权限)并提示你接受。
  4. 选择“接受”
  5. 然后,应会重定向到“<连接名称 > 的连接测试成功”页。

现在可以在机器人代码中使用此连接名称检索用户令牌。

准备机器人代码

完成此过程需要机器人的应用 ID 和密码。

  1. 从 GitHub 存储库中克隆要使用的示例:机器人身份验证

  2. 更新 appsettings.json

    • ConnectionName 设置为要添加到机器人的 OAuth 连接设置的名称。
    • MicrosoftAppIdMicrosoftAppClientId 设置为机器人的应用 ID 和应用机密。
    {
      "MicrosoftAppType": "",
      "MicrosoftAppId": "",
      "MicrosoftAppClientId": "",
      "MicrosoftAppTenantId": "",
       "ConnectionName": ""
    }
    
    

    若要配合公有云中的数据驻留在机器人中使用 OAuth,必须在 appsettings 中添加以下配置

    "OAuthUrl": "<Regional-OAuth-Uri>",
    "ToChannelFromBotOAuthScope": "https://api.botframework.azure.cn",
    "ToChannelFromBotLoginUrlTemplate": "https://api.botframework.azure.cn",
    "PublicAzureChannel": "https://api.botframework.azure.cn",
    "ToBotFromChannelOpenIdMetadataUrl": "https://login.botframework.azure.cn/v1/.well-known/openidconfiguration",
    "ToBotFromEmulatorOpenIdMetadataUrl": "https://login.partner.microsoftonline.cn/common/v2.0/.well-known/openid-configuration",
    "ToBotFromChannelTokenIssuer": "https://api.botframework.azure.cn",
    "ToChannelFromBotLoginUrl": "https://login.partner.microsoftonline.cn/botframework.com",
    
  3. 更新 Startup.cs

    若要在“非公有 Azure 云”(如政府云)中使用 OAuth,必须在 Startup.cs 文件中添加以下代码。

    string uri = "<uri-to-use>";
    MicrosoftAppCredentials.TrustServiceUrl(uri);
    OAuthClientConfig.OAuthEndpoint = uri;
    
    

    其中 <uri-to-use> 是以下 URI 之一:

    URI 说明
    https://api.botframework.azure.cn 对于由 21Vianet 云机器人运营的 Azure,无需数据驻留。

注意

现在可以将机器人代码发布到 Azure 订阅(在项目上右键选择“发布”),但本文不需要这样做。 需要设置一个发布配置,以便使用在 Azure 门户中配置机器人时使用的应用程序和托管计划。

测试

配置好身份验证机制后,就可以执行实际的机器人样本测试了。

注意

考虑到机器人示例的实现方式,系统可能会要求你输入幻码。 此幻码是 RFC#7636 的一部分,用于添加额外的安全元素。 删除幻码会增加安全风险。 这可以通过启用增强身份验证的 Direct Line 来缓解。 有关详细信息,请参阅 Bot Framework 增强身份验证

身份验证示例

机器人身份验证示例中,此对话被设计为在用户登录后检索用户令牌。

与身份验证示例机器人的对话示例。

其他信息

如果用户要求机器人执行某项操作,而该操作要求机器人让用户登录,则机器人可以使用 OAuthPrompt 来开始检索给定连接的令牌。 OAuthPrompt 创建一个令牌检索流,其中包含:

  1. 查看 Azure AI 机器人服务是否已经有一个适用于当前用户和连接的令牌。 如果有令牌,则会返回令牌。
  2. 如果 Azure AI 机器人服务没有缓存的令牌,则会创建 OAuthCard,这是一个可供用户选择的登录按钮。
  3. 在用户选择 OAuthCard 登录按钮后,Azure AI 机器人服务会直接向机器人发送用户令牌,或向用户提供一个六位数的身份验证码,让用户在聊天窗口中输入。
  4. 如果 Azure 机器人服务向用户提供身份验证代码,则机器人会用此身份验证代码来交换获取用户的令牌。

以下部分描述示例如何执行某些常见的身份验证任务。

使用 OAuth 提示来登录用户并获取令牌

C# 示例的体系结构示意图。

Dialogs\MainDialog.cs

将 OAuth 提示添加到其构造函数中的 MainDialog。 在这里,连接名称的值已从 appsettings.json 文件中检索。

AddDialog(new OAuthPrompt(
    nameof(OAuthPrompt),
    new OAuthPromptSettings
    {
        ConnectionName = ConnectionName,
        Text = "Please Sign In",
        Title = "Sign In",
        Timeout = 300000, // User has 5 minutes to login (1000 * 60 * 5)
    }));

在对话步骤中,请使用 BeginDialogAsync 来启动 OAuth 提示,该提示要求用户登录。

  • 如果用户已经登录,则无需提示用户,而是直接生成令牌响应事件。 否则,系统会提示用户登录。 在用户尝试登录后,Azure AI 机器人服务会发送令牌响应事件。
return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);

在以下对话步骤中,检查上一步的结果中是否存在令牌。 如果该令牌不为 null,则表明用户已成功登录。

// Get the token from the previous step. Note that we could also have gotten the
// token directly from the prompt itself. There is an example of this in the next method.
var tokenResponse = (TokenResponse)stepContext.Result;

等待 TokenResponseEvent

启动 OAuth 提示时,它会等待令牌响应事件,并从中检索用户的令牌。

Bots\AuthBot.cs

AuthBot 派生自 ActivityHandler,会显式处理令牌响应事件活动。 在这里,我们会继续活动对话,这样 OAuth 提示就能处理事件并检索令牌。

protected override async Task OnTokenResponseEventAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
{
    Logger.LogInformation("Running dialog with Token Response Event Activity.");

    // Run the Dialog with the new Token Response Event Activity.
    await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}

注销用户

最佳做法是让用户显式退出登录,而不是等待连接超时。

Dialogs\LogoutDialog.cs

private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
{
    if (innerDc.Context.Activity.Type == ActivityTypes.Message)
    {
        var text = innerDc.Context.Activity.Text.ToLowerInvariant();

        if (text == "logout")
        {
            // The UserTokenClient encapsulates the authentication processes.
            var userTokenClient = innerDc.Context.TurnState.Get<UserTokenClient>();
            await userTokenClient.SignOutUserAsync(innerDc.Context.Activity.From.Id, ConnectionName, innerDc.Context.Activity.ChannelId, cancellationToken).ConfigureAwait(false);

            await innerDc.Context.SendActivityAsync(MessageFactory.Text("You have been signed out."), cancellationToken);
            return await innerDc.CancelAllDialogsAsync(cancellationToken);
        }
    }

    return null;
}

其他阅读材料