將單一登錄新增至 Bot
適用於: SDK v4
本文說明如何在 Bot 中使用單一登錄 (SSO) 功能。 若要這樣做,這項功能會使用 取用者 Bot,也稱為 根 或 父 Bot,與 技能 或 子 Bot 互動。 本文使用根 Bot 和技能 Bot 一詞。
如果您包含 SSO 支援,使用者可以使用身分識別提供者登入根 Bot,而且當控制傳遞至技能時,不需要再次登入。
根和技能 Bot 是個別的 Bot,可在可能不同的伺服器上執行,每個伺服器都有自己的個別記憶體和狀態。 如需技能的詳細資訊,請參閱 技能概觀 和 實作技能。 如需使用者驗證的詳細資訊,請參閱 Bot Framework 驗證基本概念、 使用者驗證和 將驗證新增至 Bot。
重要
當您搭配 網路聊天 使用 Azure AI Bot Service 驗證時,必須牢記一些重要的安全性考慮。 如需詳細資訊,請參閱 REST 驗證一文中的安全性考慮 一節。
必要條件
- Bot 基本概念、 管理狀態和 關於單一登錄的知識。
- 對話連結庫的知識,以及如何實作循序對話流程和重複使用對話
- 瞭解 Azure 和 OAuth 2.0 開發。
- 適用於 .NET 的 Visual Studio 2019 或更新版本。
- 具有簡單技能取用者和 C# 技能的 SSO。
關於範例
本文參考兩個 Bot: RootBot 和 SkillBot。 RootBot 會將活動轉送至 SkillBot。 他們會建立此 一般 技能案例的模型:
- 根 Bot 會呼叫一或多個技能 Bot。
- 根和技能 Bot 都會實作將驗證新增至 Bot 一文中所述的基本驗證。
- 用戶登入根 Bot。
- 由於 SSO 已登入根 Bot,因此他們已登入技能 Bot,而不需要再次進行用戶互動。
如需 Bot Framework 如何處理驗證的概觀,請參閱 用戶驗證。 如需 SSO 背景資訊,請參閱 單一登錄。
RootBot 支援 SSO。 它會代表使用者與 SkillBot 通訊,而不需要使用者再次向_SkillBot進行驗證。
針對範例中的每個專案,您需要下列專案:
- Microsoft Entra ID 應用程式,以在 Azure 中註冊 Bot 資源。
- 用於驗證的Microsoft Entra ID 識別提供者應用程式。
注意
目前僅 支援Microsoft Entra ID 識別提供者。
建立 Azure RootBot 資源
建立 RootBot 的Microsoft專案識別碼身分識別
Microsoft Entra ID 是雲端身分識別服務,可讓您建置應用程式,以使用 OAuth2.0 等業界標準通訊協定安全地登入使用者。
為
RootBot
建立身分識別應用程式,以使用 Microsoft Entra 識別碼來驗證使用者。 請遵循建立 Microsoft Entra ID 識別提供者中所述的步驟。在左窗格中,選取 [ 指令清單]。
設定
accessTokenAcceptedVersion
為 2。選取儲存。
在左窗格中,選取 [ 公開 API]。
在右窗格中,選取 [新增範圍]。
在最右邊 的 [新增範圍] 區段上,選取 [ 儲存並繼續]。
在顯示的視窗中,於 [誰可以同意?] 底下,選取 [系統管理員和使用者]。
輸入其餘的必要資訊。
選取 [新增範圍]。
複製並儲存範圍值。
建立 RootBot 的 OAuth 連線設定
在 Bot 註冊中
RootBot
建立Microsoft Entra ID 連線,並輸入值,如 Microsoft Entra ID 和以下所述的值所述。將 令牌交換 URL 保留空白。
在 [ 範圍] 方塊中 ,輸入
RootBot
您在先前步驟中儲存的範圍值。注意
範圍包含使用者一開始登入根 Bot 的 URL,而令牌交換 URL 則保留空白。
例如,假設根 Bot appid 是 rootAppId ,而技能 Bot appid 是 skillAppId。 根 Bot 的範圍 看起來會像 api://rootAppId/customScope,用來登入使用者。 接著, 此根 Bot 的範圍 會在 SSO 期間與 api://skillAppId/customscope 交換。
複製並儲存連接的名稱。
建立 Azure SkillBot 資源
建立 SkillBot 的Microsoft Entra ID 身分識別
Microsoft Entra ID 是雲端身分識別服務,可讓您建置應用程式,以使用 OAuth2.0 等業界標準通訊協定安全地登入使用者。
為
SkillBot
建立識別應用程式,以使用 Microsoft Entra 識別碼來驗證 Bot。 請遵循建立 Microsoft Entra ID 識別提供者中所述的步驟。在左窗格中,選取 [ 指令清單]。
設定
accessTokenAcceptedVersion
為 2。選取儲存。
在左窗格中,選取 [ 公開 API]。
在右窗格中,選取 [新增範圍]。
在最右邊 的 [新增範圍] 區段中,選取 [ 儲存並繼續]。
在顯示的視窗中,於 [誰可以同意?] 底下,選取 [系統管理員和使用者]。
輸入其餘的必要資訊。
選取 [新增範圍]。
複製並儲存範圍值。
選取新增用戶端應用程式。 在最右邊的區段中,於 [用戶端標識符] 方塊中,輸入您之前儲存的 RootBot 身分識別應用程式識別碼。 請確定您使用 RootBot 身分識別,而不是註冊應用程式識別碼。
注意
針對用戶端應用程式,Azure AI Bot Service 不支援搭配 Microsoft Entra ID B2C 識別提供者的單一唱對。
在 [授權的範圍] 底下,依範圍值核取方塊。
選取 [新增應用程式]。
在左側瀏覽窗格中,選取 [API 許可權]。 最佳做法是明確設定應用程式的 API 許可權。
在右窗格中,選取 [ 新增許可權]。
選取 [Microsoft API ],然後 Microsoft Graph。
選擇 [委派的許可權 ],並確定已選取所需的許可權。 此範例需要下列許可權。
注意
任何標示為 「需要 管理員同意」的許可權都需要使用者和租用戶系統管理員登入。
- openid
- profile
- User.Read
- User.ReadBasic.All
選取 [新增權限]。
建立 SkillBot 的 OAuth 連線設定
在 Bot 註冊中
SkillBot
建立Microsoft Entra ID 連線,並輸入值,如 Microsoft Entra ID 和以下所述的值所述。在 [ 令牌交換 URL] 方塊中,輸入
SkillBot
您在先前步驟中儲存的範圍值。在 [範圍] 方塊中,輸入下列以空白分隔的值:
openid
profile
User.ReadBasic.All
User.Read
。複製並儲存至連接名稱的檔案。
測試連線
- 選取連線項目以開啟您所建立的連接。
- 選取 [服務提供者連線設定] 窗格頂端的 [測試連線]。
- 第一次,這應該會開啟新的瀏覽器索引標籤,其中列出您的應用程式要求的許可權,並提示您接受。
- 選取 [接受]。
- 然後,這應該會將您重新導向至 [測試連線] 至 <您的連線名稱> [ 成功] 頁面。
如需詳細資訊,請參閱適用於開發人員的Microsoft專案標識符概觀和 Microsoft 身分識別平台 (v2.0) 概觀。 如需 v1 和 v2 端點之間差異的相關信息,請參閱為什麼更新為 Microsoft 身分識別平台 (v2.0)?。 如需完整資訊,請參閱 Microsoft 身分識別平台(先前為開發人員Microsoft Entra ID)。
準備範例程序代碼
您必須更新 appsettings.json
這兩個範例中的檔案,如下所示。
從 GitHub 存放 庫複製具有簡單技能取用者和技能 範例的 SSO。
SkillBot
開啟項目appsettings.json
檔。 從儲存的檔案指派下列值:{ "MicrosoftAppId": "<SkillBot registration app ID>", "MicrosoftAppPassword": "<SkillBot registration password>", "ConnectionName": "<SkillBot connection name>", "AllowedCallers": [ "<RootBot registration app ID>" ] }
RootBot
開啟項目appsettings.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
命令login
可讓使用者使用RootBot
登入 Microsoft Entra ID 註冊。 登入之後,SSO 也會負責登入SkillBot
。 使用者不需要再次登入。token
會顯示使用者的令牌。logout
將使用者登出RootBot
。
SkillBot
命令skill login
RootBot
允許 代表使用者登入SkillBot
。 如果用戶已經登入,除非 SSO 失敗,否則不會顯示登入卡。skill token
會從SkillBot
顯示使用者的令牌。skill logout
將用戶註銷SkillBot
注意
使用者第一次嘗試使用 SSO 進行技能時,可能會看到要登入的 OAuth 卡片。 這是因為他們尚未同意技能的 Microsoft Entra ID 應用程式。 若要避免這種情況,他們可以為 Microsoft Entra ID 應用程式所要求的任何圖形許可權授與系統管理員同意。
如果您尚未這麼做,請安裝 Bot Framework 模擬器。 另 請參閱使用模擬器進行偵錯。
您必須將模擬器設定為 Bot 範例登入才能運作。 使用下列步驟:如設定模擬器以進行驗證所示。
設定驗證機制之後,您可以執行實際的 Bot 範例測試。
在 Visual Studio 中
SSOWithSkills.sln
,開啟方案,並將其設定為使用多個進程開始偵錯。在本機電腦上開始偵錯。 請注意,在項目
appsettings.json
檔中RootBot
,您有下列設定:"SkillHostEndpoint": "http://localhost:3978/api/skills/" "SkillEndpoint": "http://localhost:39783/api/messages"
注意
這些設定表示在本機電腦上同時
RootBot
執行 和SkillBot
。 模擬器會在埠 3978 上與RootBot
通訊,並在RootBot
埠 39783 上與SkillBot
通訊。 一旦您開始偵錯,就會開啟兩個默認瀏覽器視窗。 埠 3978 上的一個,另一個位於埠 39783。啟動模擬器。
當您連線到 Bot 時,請輸入註冊
RootBot
應用程式識別碼和密碼。輸入
hi
以開始交談。輸入 登入。
RootBot
會顯示登入 AAD 驗證卡。選取 [登入]。 快顯對話框 [確認開啟 URL ] 隨即顯示。
選取確認。 您將登入,並
RootBot
顯示令牌。輸入 Token 以再次顯示令牌。
現在您已準備好與
SkillBot
通訊。 使用 簽署RootBot
之後,您不需要再次提供認證,直到註銷為止。這示範 SSO 運作正常。在 [模擬器] 方塊中輸入 技能登入 。 系統不會要求您再次登入。 而是會顯示 SkillBot 令牌。
輸入 技能令牌 以再次顯示令牌。
現在您可以輸入 技能註銷 以登出
SkillBot
。 然後輸入 註銷 以登出SimpleRootBoot
。
其他資訊
下列時序圖適用於本文中使用的範例,並顯示涉及的各種元件之間的互動。 ABS 代表 Azure AI Bot Service。
- 使用者第一次輸入
login
RootBot 的命令。 - RootBot 會傳送 OAuthCard,要求使用者登入。
- 使用者輸入傳送至 ABS 的驗證認證(Azure AI Bot Service)。
- ABS 會將根據使用者的認證產生的驗證令牌傳送至 RootBot。
- RootBot 會顯示使用者要查看的根令牌。
- 用戶輸入
skill login
SkillBot 的命令。 - SkillBot 會將 OAuthCard 傳送至 RootBot。
- RootBot 會向 ABS 要求可交換的令牌。
- SSO 會將 SkillBot 技能令牌傳送至 RootBot。
- RootBot 會顯示使用者的技能令牌。 請注意,已產生技能令牌,而不需要使用者登入 SKillBot。 這是因為 SSO。
下列範例示範令牌交換的發生方式。 程式代碼來自 TokenExchangeSkillHandler.cs 檔案。
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;
}