category
本文展示了如何在机器人中使用单点登录(SSO)功能。为此,此功能使用消费者机器人(也称为根或父机器人)与技能或子机器人进行交互。本文使用了根机器人和技能机器人这两个术语。
如果包含SSO支持,则用户可以使用身份提供程序登录到根机器人,并且在控制权传递给技能时不需要再次登录。
根机器人和技能机器人是独立的机器人,运行在可能不同的服务器上,每个服务器都有自己独立的内存和状态。有关技能的更多信息,请参阅技能概述和实施技能。有关用户身份验证的更多信息,请参阅Bot Framework身份验证基础、用户身份验证和向机器人添加身份验证。
重要事项
当您在Web聊天中使用Azure AI Bot Service身份验证时,必须记住一些重要的安全考虑因素。有关更多信息,请参阅REST身份验证文章中的安全考虑部分。
先决条件
- 了解机器人基础知识、管理状态和关于单点登录。
- 了解对话库以及如何实现顺序对话流和重用对话
- 了解Azure和OAuth 2.0开发。
- Visual Studio 2019或更高版本.NET.。
- SSO具有简单的skill consumer和C#技能。
关于样品
本文引用了两个机器人:RootBot和SkillBot。RootBot将活动转发给SkillBot。他们模拟了这种典型的技能场景:
- 根机器人调用一个或多个技能机器人。
- 根机器人和技能机器人都实现了在向机器人添加身份验证文章中描述的基本身份验证。
- 用户登录到root bot。
- 由于SSO并且已经登录到根机器人,他们无需再次进行用户交互即可登录到技能机器人。
有关Bot Framework如何处理身份验证的概述,请参阅用户身份验证。有关SSO背景信息,请参阅单点登录。
RootBot支持单点登录。它代表用户与SkillBot通信,而无需用户再次在_SkillBot中进行身份验证。
对于示例中的每个项目,您需要以下内容:
- 用于在Azure中注册机器人资源的Microsoft Entra ID应用程序。
- 用于身份验证的Microsoft Entra ID身份提供程序应用程序。
注:
目前,仅支持Microsoft Entra ID身份提供程序。
创建Azure RootBot资源
- 在Azure门户中为RootBot创建Azure bot资源。按照创建Azure bot资源中描述的步骤进行操作。
- 复制并保存机器人注册应用程序ID和客户端密钥。
为RootBot创建Microsoft Entra ID标识
Microsoft Entra ID是一种云身份服务,允许您使用OAuth2.0等行业标准协议构建安全登录用户的应用程序。
- 为RootBot创建一个身份应用程序,该应用程序使用Microsoft Entra ID对用户进行身份验证。按照创建Microsoft Entra ID身份提供程序中描述的步骤进行操作。
- 在左侧窗格中,选择Manifest。
- 将accessTokenAcceptedVersion设置为2。
- 选择保存。
- 在左侧窗格中,选择“公开API”。
- 在右侧窗格中,选择添加范围。
- 在最右侧的“添加作用域”部分,选择“保存”并继续。
- 在显示的窗口中,在“谁可以同意?”下?,选择管理员和用户。
- 输入剩余的必填信息。
- 选择添加范围。
- 复制并保存作用域值。
为RootBot创建OAuth连接设置
- 在RootBot机器人注册中创建一个Microsoft Entra ID连接,并按照Microsoft Entra标识和下面描述的值输入值。
- 将令牌交换URL留空。
- 在“作用域”框中,输入您在前面步骤中保存的RootBot作用域值。
注:
Scopes包含用户最初登录到根机器人的URL,而令牌交换URL为空。
作为一个例子,让我们假设根机器人应用程序ID是rootAppId,技能机器人应用程序id是skillAppId。根机器人的作用域如下api://rootAppId/customScope,用于登录用户。然后将此根机器人的作用域与以下对象交换api://skillAppId/customscope在SSO期间。
复制并保存连接的名称。
创建Azure SkillBot资源
- 在Azure门户中为SkillBot创建Azure机器人资源。按照创建Azure bot资源中描述的步骤进行操作。
- 复制并保存机器人注册应用程序ID和客户端密钥。
为SkillBot创建Microsoft Entra ID标识
Microsoft Entra ID是一种云身份服务,允许您使用OAuth2.0等行业标准协议构建安全登录用户的应用程序。
- 为SkillBot创建一个身份应用程序,该应用程序使用Microsoft Entra ID对机器人进行身份验证。按照创建Microsoft Entra标识提供程序中描述的步骤进行操作。
- 在左侧窗格中,选择Manifest。
- 将accessTokenAcceptedVersion设置为2。
- 选择保存。
- 在左侧窗格中,选择“公开API”。
- 在右侧窗格中,选择添加范围。
- 在最右侧的“添加作用域”部分,选择“保存”并继续。
- 在显示的窗口中,在“谁可以同意”下?选择管理员和用户。
- 输入剩余的必填信息。
- 选择添加范围。
- 复制并保存作用域值。
- 选择添加客户端应用程序。在最右侧的“客户端ID”框中,输入您之前保存的RootBot身份应用程序ID。请确保使用RootBot标识,而不是注册应用程序ID。
- 注:
- 对于客户端应用程序,Azure AI Bot Service不支持与Microsoft Entra ID B2C身份提供者进行单点登录。
- 在“授权范围”下,按范围值选中复选框。
- 选择添加应用程序。
- 在左侧的导航窗格中,选择API权限。显式设置应用程序的API权限是最佳做法。
- 在右侧窗格中,选择添加权限。
- 选择Microsoft API,然后选择Microsoft Graph。
- 选择“委派权限”,并确保已选择所需的权限。此示例需要下面列出的权限。
注:
任何标记为“需要管理员同意”的权限都需要用户和租户管理员登录。
- openid
- profile
- User.Read
- User.ReadBasic.All
-
Select Add permissions.
为SkillBot创建OAuth连接设置
- 在SkillBot机器人注册中创建一个Microsoft Entra ID连接,并按照Microsoft Entra IDs和下面描述的值输入值。
- 在令牌交换URL框中,输入您在前面步骤中保存的SkillBot作用域值。
- 在“范围”框中,输入以下值,用空格分隔:profile User。读取用户。阅读基础。全部开放。
- 将连接的名称复制并保存到文件中。
测试连接
- 在连接条目上选择以打开您创建的连接。
- 在“服务提供商连接设置”窗格顶部选择“测试连接”。
- 第一次,这应该会打开一个新的浏览器选项卡,列出您的应用程序正在请求的权限,并提示您接受。
- 选择接受。
- 然后,这应该会将您重定向到<您的连接名称>成功页面的测试连接。
有关更多信息,请参阅面向开发人员的Microsoft Entra ID(v1.0)概述和Microsoft身份平台(v2.0)概述。有关v1和v2端点之间差异的信息,请参阅为什么更新到Microsoft身份平台(v2.0)?。有关完整信息,请参阅Microsoft身份平台(以前为开发人员提供的Microsoft Entra ID)。
准备样本代码
您必须按照如下所述更新这两个示例中的appset.json文件。
- 从GitHub存储库中克隆带有简单技能消费者和技能示例的SSO。
- 打开SkillBot项目apps.json文件。从保存的文件中指定以下值:
JSON
{
"MicrosoftAppId": "<SkillBot registration app ID>",
"MicrosoftAppPassword": "<SkillBot registration password>",
"ConnectionName": "<SkillBot connection name>",
"AllowedCallers": [ "<RootBot registration app ID>" ]
}
- 打开RootBot项目apps.json文件。从保存的文件中指定以下值:
JSON
{
"MicrosoftAppId": "<RootBot registration app ID>",
"MicrosoftAppPassword": "<RootBot registration password>",
"ConnectionName": "<RootBot connection name>",
"SkillHostEndpoint": "http://localhost:3978/api/skills/",
"BotFrameworkSkills": [
{
"Id": "SkillBot",
"AppId": "<SkillBot registration app ID>",
"SkillEndpoint": "http://localhost:39783/api/messages"
}
]
}
测试样品
使用以下内容进行测试:
RootBot命令
- 登录允许用户使用RootBot登录到Microsoft Entra ID注册。登录后,SSO也会负责登录SkillBot。用户不必再次登录。
- token显示用户的token。
- 注销将用户从RootBot中注销。
SkillBot命令
- 技能登录允许RootBot代表用户登录SkillBot。如果用户已经登录,则不会显示登录卡,除非SSO失败。
- 技能令牌显示来自SkillBot的用户令牌。
- 技能注销将用户从SkillBot中注销
注:
用户首次在技能上尝试SSO时,可能会收到OAuth卡以登录。这是因为他们尚未同意该技能的Microsoft Entra ID应用程序。为了避免这种情况,他们可以对Microsoft Entra ID应用程序请求的任何图形权限授予管理员同意。
仿真器
网络聊天
如果您还没有这样做,请安装Bot Framework模拟器。另请参见使用模拟器进行调试。
您需要配置模拟器,以便机器人示例登录正常工作。使用以下步骤:如配置模拟器进行身份验证所示。
配置身份验证机制后,您可以执行实际的机器人示例测试。
- 在Visual Studio中,打开SSOWithSkills.sln解决方案,并将其配置为开始使用多个进程进行调试。
- 在您的计算机上开始本地调试。请注意,在RootBot项目apps.json文件中,您有以下设置:
JSON
"SkillHostEndpoint": "http://localhost:3978/api/skills/"
"SkillEndpoint": "http://localhost:39783/api/messages"
注:这些设置意味着,RootBot和SkillBot都在本地计算机上运行。Emulator通过端口3978与RootBot通信,RootBot通过端口39783与SkillBot通信。一旦开始调试,就会打开两个默认浏览器窗口。一个在端口3978上,另一个在港口39783上。
- 启动模拟器。
- 当您连接到机器人时,请输入您的RootBot注册应用程序ID和密码。
- 键入hi开始对话。
- 输入登录名。RootBot将显示登录到AAD身份验证卡。
登录卡示例。
- 选择登录。将显示弹出对话框确认打开URL。
“打开URL”确认消息的屏幕截图。
- 选择确认。您将登录并显示RootBot令牌。
- 输入令牌以再次显示令牌。
显示根令牌的消息示例。
现在,您已准备好与SkillBot进行通信。使用RootBot签名后,在注销之前,您不需要再次提供凭据。这表明SSO正在工作。
- 在Emulator框中输入技能登录。系统不会要求您再次登录。取而代之的是显示SkillBot令牌。
- 输入技能令牌以再次显示令牌。
- 现在,您可以输入技能注销以退出SkillBot。然后输入logout退出SimpleRootBoot。
附加信息
以下时间序列图适用于本文中使用的示例,并显示了所涉及的各个组件之间的交互。ABS代表Azure AI机器人服务。
显示技能令牌流的序列图。
- 第一次,用户输入RootBot的登录命令。
- RootBot发送一个OAuthCard请求用户登录。
- 用户输入发送到ABS(Azure AI Bot Service)的身份验证凭据。
- ABS将基于用户凭据生成的身份验证令牌发送给RootBot。
- RootBot显示根令牌供用户查看。
- 用户输入SkillBot的技能登录命令。
- SkillBot向RootBot发送一个OAuthCard。
- RootBot要求ABS提供可交换令牌。
- SSO将SkillBot技能令牌发送给RootBot。
- RootBot显示技能令牌供用户查看。请注意,技能令牌是在用户不必登录SKillBot的情况下生成的。这是因为SSO。
以下示例显示了令牌交换是如何发生的。代码来自TokenExchangeSkillHandler.cs文件。
C#
private async Task<bool> InterceptOAuthCards(ClaimsIdentity claimsIdentity, Activity activity)
{
var oauthCardAttachment = activity.Attachments?.FirstOrDefault
(a => a?.ContentType == OAuthCard.ContentType);
if (oauthCardAttachment != null)
{
var targetSkill = GetCallingSkill(claimsIdentity);
if (targetSkill != null)
{
var oauthCard = ((JObject)oauthCardAttachment.Content).ToObject<OAuthCard>();
if (!string.IsNullOrWhiteSpace(oauthCard?.TokenExchangeResource?.Uri))
{
using (var context = new TurnContext(_adapter, activity))
{
context.TurnState.Add<IIdentity>("BotIdentity", claimsIdentity);
// AAD token exchange
try
{
var result = await _tokenExchangeProvider.ExchangeTokenAsync(
context,
_connectionName,
activity.Recipient.Id,
new TokenExchangeRequest()
{ Uri = oauthCard.TokenExchangeResource.Uri }).ConfigureAwait(false);
if (!string.IsNullOrEmpty(result?.Token))
{
// If token above is null, then SSO has failed and hence we return false.
// If not, send an invoke to the skill with the token.
return await SendTokenExchangeInvokeToSkill(activity,
oauthCard.TokenExchangeResource.Id,
result.Token,
oauthCard.ConnectionName,
targetSkill, default).ConfigureAwait(false);
}
}
catch
{
// Show oauth card if token exchange fails.
return false;
}
return false;
}
}
}
}
return false;
}
- 登录 发表评论
- 4 次浏览
Tags
最新内容
- 2 days 15 hours ago
- 2 days 15 hours ago
- 2 days 15 hours ago
- 2 days 15 hours ago
- 2 days 16 hours ago
- 2 days 16 hours ago
- 2 days 17 hours ago
- 2 days 17 hours ago
- 4 days 4 hours ago
- 4 days 5 hours ago