本文內容
Copilot Studio 支援單一登入 (SSO)。 SSO 允許您網站上的代理在客戶已經登錄到部署了專員的頁面或應用程式時登錄。
例如,專員託管在公司 Intranet 或使用者已登錄的應用程式中。
為 Copilot Studio 設定 SSO 有四個主要步驟:
在 Microsoft Entra ID 中建立自訂畫布的應用程式註冊。
為您的專員定義自定義範圍。
在 Copilot Studio 中設定驗證以啟用 SSO。
設定您的自訂畫布 HTML 代碼以啟用 SSO。
先決條件
支援的管道
下表詳細描述目前支援 SSO 的管道 。 您可以在 the 構想論壇上建議對額外頻道 Copilot Studio 的支援 。
1 如果您還啟用了 Teams 通道,則需要跟隨文檔中的使用 ID 為代理 配置單 Microsoft Entra 點登錄中的配置說明 Microsoft Teams 。 如果無法根據該頁面上的指示設定 Teams SSO 設定,會導致您的使用者在使用 Teams 管道時一直無法通過驗證。
2 只支援即時聊天管道。 如需其他資訊,請參閱設定移交至 Dynamics 365 Customer Service 。
重要
當專員已滿足以下任一條件時,當前不支援 SSO:
但是,已作為 SharePoint SPFx 元件 發佈到 網站的專員支援 SSO。
建立自訂網站的應用程式註冊
若要啟用 SSO,您需要建立兩個不同的應用程式註冊:
身份驗證 應用程式註冊 ,為您的 # 啟用 Microsoft Entra ID 使用者身份驗證專員
畫布應用程式註冊 ,這會為自訂網頁啟用 SSO
出於安全原因,我們不建議對專員和自定義網站重複使用相同的應用程式註冊。
依照使用 Microsoft Entra ID 設定使用者驗證中的說明建立驗證應用程式註冊。
再次按照建立驗證應用程式註冊說明建立第二個應用程式註冊,用作畫布應用程式註冊。
將畫布應用程式註冊識別碼新增至驗證應用程式註冊。
新增權杖交換 URL
若要更新 Copilot Studio 中的 Microsoft Entra ID 驗證設定,您需要新增權杖交換 URL,以允許您的應用程式和 Copilot Studio 共用資訊。
在驗證應用程式註冊側邊欄標籤上的 Azure 入口網站中,前往公開 API 。
在範圍 下,選擇複製到剪貼簿 圖示。
在 Copilot Studio 導覽功能表的設定 底下,選取安全性 ,然後選取驗證 圖標。
在權杖交換 URL (SSO 的必要項) 中,將先前複製的範圍貼上。
選取儲存 。
建立畫布應用程式註冊之後,移至驗證 ,然後選取新增平台 。
在平台 設定底下,選取新增平台 ,然後選取 Web 。
在重新導向 URL 底下,輸入網頁的 URL;例如,http://contoso.com/index.html
。
在隱含授與和混合流程 區段中,開啟存取權杖 (用於隱含流程) 和識別碼權杖 (用於隱含和混合流程) 。
選取設定 。
在 URL 端點查找專員的令牌
在中 Copilot Studio,打開您的專員然後選擇 Channels 。
選取行動裝置應用程式 。
在權杖端點 底下,選取複製 。
在網頁中設定 SSO
使用 Copilot Studio GitHub 存放庫 提供的程式碼,建立重新導向 URL 的網頁。 從 GitHub 儲存庫複製代碼,並按照以下說明對其進行修改。
注意
GitHub 存放庫中的程式碼要求使用者選擇登錄按鈕或從其他網站登錄。 若要啟用自動登入,請將以下程式碼新增至 aysnc function main()
的開頭:
(async function main() {
if (clientApplication.getAccount() == null) {
await clientApplication.loginPopup(requestObj).then(onSignin).catch(function (error) {console.log(error) });
}
// Add your BOT ID below
var theURL =
前往 Azure 入口網站中的概觀 頁面,並複製畫布應用程式註冊中的應用程式 (用戶端) 識別碼 和目錄 (租用戶) 識別碼 。
若要設定 Microsoft 驗證庫 (MSAL):
指派 clientId
給您的應用程式 (用戶端) 識別碼 。
指派 authority
至 https://login.microsoftonline.com/
並將目錄 (租用戶) 識別碼新增 至結尾。
例如:
var clientApplication;
(function (){
var msalConfig = {
auth: {
clientId: '00001111-aaaa-2222-bbbb-3333cccc4444',
authority: 'https://login.microsoftonline.com/7ef988bf-xxxx-51af-01ab-2d7fd011db47'
},
將 theURL
變數設定為先前複製的權杖端點 URL。 例如:
(async function main() {
var theURL = "https://<token endpoint URL>"
編輯 userId
的值以加入自訂首碼。 例如:
var userId = clientApplication.account?.accountIdentifier != null ?
("My-custom-prefix" + clientApplication.account.accountIdentifier).substr(0, 64)
: (Math.random().toString() + Date.now().toString()).substr(0,64);
儲存您的變更。
使用網頁測試專員
在瀏覽器中打開網頁。
選取登入 。
注意
如果您的瀏覽器封鎖快顯視窗,或者您使用的是無痕瀏覽或私密瀏覽視窗,系統會提示您登入。 否則,將使用驗證碼完成登入。
新的瀏覽器索引標籤會開啟。
切換至新的索引標籤,並複製驗證代碼。
切換回帶有專員的選項卡,然後將驗證代碼粘貼到專員對話中。
相關內容
技術概觀
下列圖解顯示使用者如何登入,而不會在 Copilot Studio 中看到登入提示 (SSO):
專員使用者輸入觸發登錄主題 的短語 。 登入主題的設計目的是為了讓使用者登入,並使用使用者的已驗證權杖 (User.AccessToken
變數) 。
Copilot Studio 傳送登入提示,允許使用者以其設定的識別提供者登入。
專員的 自定義畫布 會攔截登錄提示,並從 ID 請求代表 (OBO) 令牌 Microsoft Entra 。 畫布將令牌發送到專員。
收到 OBO 令牌後,專員將 OBO 令牌交換為“存取權杖”,並使用存取權杖的值填充 AuthToken
變數。 此時也會設定 IsLoggedIn
變數。
在 Microsoft Entra ID 中建立自訂畫布的應用程式註冊
若要啟用 SSO,您需要兩個不同的應用程式註冊:
重要
您不能對專員的使用者身份驗證和自訂畫布重複使用同一應用程式註冊。
為專員的畫布創建應用程式註冊
登入 Azure 入口網站 。
若要移至應用程式註冊 ,請選取圖示或在頂端搜尋欄中搜尋。
選取新增註冊 。
輸入註冊的名稱。 使用要註冊其畫布的專員的名稱並包含“canvas”以説明將其與應用程式註冊分開進行身份驗證,這可能會很有説明。
例如,如果您的專員稱為“Contoso sales help”,則可以將應用程式註冊命名為“ContosoSalesCanvas”或類似名稱。
在支援的帳戶類型 中選取任何組織用戶端中的帳戶 (任何 Microsoft Entra ID 目錄 - 多用戶端) 和個人 Microsoft 帳戶 (例如 Skype、Xbox) 。
目前將重新導向 URI 區段保留空白,將在後續步驟中輸入該資訊。 選取註冊 。
註冊完成後,會開啟概觀 頁面。 移至清單 。 確認 accessTokenAcceptedVersion
設定為 2
。 如果不是,請將它變更為 2
,然後選取儲存 。
新增重新導向 URL
在註冊開放後,前往驗證 然後選取新增平臺 。
在設定平台 刀鋒視窗中,選取 Web 。
在重新導向 URI 下,將完整 URL 新增至您的聊天畫布被託管的頁面。 在隱含授與 區段中,選取 識別碼權杖 和存取權杖 核取方塊。
選取設定 以確認變更。
移至 API 權限 。 選取代表 <您的用戶名稱> 授與管理員同意 然後是 。
重要
若要避免使用者同意每個應用程式,全域系統管理員、應用程式系統管理員或雲端應用程式管理員必須將用戶範圍的同意 授與您的應用程式註冊。
為您的 #定义自定义范围專員
透過為驗證應用程式註冊中的畫布應用程式註冊公開 API,以定義自訂範圍。 範圍 可讓您判斷使用者和管理角色以及存取權限。
此步驟會在驗證應用程式註冊和自訂畫布的應用程式註冊之間建立信任關係。
開啟您在設定驗證時 所建立的應用程式註冊。
轉到 API 許可權 並確保為您的專員添加了正確的許可權。 選取代表 <您的用戶名稱> 授與管理員同意 然後是 。
重要
若要避免使用者同意每個應用程式,全域系統管理員、應用程式系統管理員或雲端應用程式管理員必須將用戶範圍的同意 授與您的應用程式註冊。
移至公開 API 並選取新增範圍 。
輸入範圍的名稱,以及在使用者進入 SSO 畫面時,應該向使用者顯示的資訊。 選取新增範圍 。
選取新增用戶端應用程式 。
從畫布應用程式註冊的概觀 頁面,將應用程式 (用戶端) 識別碼 輸入至用戶端識別碼 欄位。 選取所建立之列出範圍的核取方塊。
選取新增應用程式 。
Copilot Studio 驗證設定頁面中的權杖交換 URL 用於透過機器人框架,交換 OBO 權杖和要求的存取權杖。
Copilot Studio 呼叫 Microsoft Entra ID 以執行實際的交換。
登入 Copilot Studio。
通過選擇頂部功能表上的專員圖示並選擇正確的專員,確認您已選擇要為其啟用身份驗證的專員。
在導覽功能表的設定 底下,選取安全性 。 接著選取驗證 卡片。
在令牌 交換 URL 字段中輸入專員的身份驗證應用程式註冊的公開 API 邊欄選項卡中的完整範圍 URI。 URI 的格式為 api://1234-4567/scope.name
。
選擇 保存 ,然後發佈專員內容。
更新專員所在的自定義畫布頁面,攔截登錄卡片請求並兌換 OBO Token。
將下列程式碼新增至 <head> 區段的 <script> 標記中,即可設定 Microsoft 驗證程式庫 (MSAL)。
使用畫布應用程式註冊的應用程式 (用戶端) 識別碼 更新 clientId
。 將 <Directory ID>
取代為目錄 (租用戶) 識別碼 。 您可以從畫布應用程式註冊的概觀 頁面取得這些識別碼。
<head>
<script>
var clientApplication;
(function () {
var msalConfig = {
auth: {
clientId: '<Client ID [CanvasClientId]>',
authority: 'https://login.microsoftonline.com/<Directory ID>'
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false
}
};
if (!clientApplication) {
clientApplication = new Msal.UserAgentApplication(msalConfig);
}
} ());
</script>
</head>
在 <body> 區段中插入下列 <script>。 此指令碼會呼叫方法,擷取 resourceUrl
並將您目前的權杖交換為 OAuth 提示要求的權杖。
<script>
function getOAuthCardResourceUri(activity) {
if (activity &&
activity.attachments &&
activity.attachments[0] &&
activity.attachments[0].contentType === 'application/vnd.microsoft.card.oauth' &&
activity.attachments[0].content.tokenExchangeResource) {
// asking for token exchange with Microsoft Entra ID
return activity.attachments[0].content.tokenExchangeResource.uri;
}
}
function exchangeTokenAsync(resourceUri) {
let user = clientApplication.getAccount();
if (user) {
let requestObj = {
scopes: [resourceUri]
};
return clientApplication.acquireTokenSilent(requestObj)
.then(function (tokenResponse) {
return tokenResponse.accessToken;
})
.catch(function (error) {
console.log(error);
});
}
else {
return Promise.resolve(null);
}
}
</script>
在 <body> 區段中插入下列 <script>。 在該方法中 main
,此代碼向 your store
添加一個條件,其中包含專員的唯一標識符。 它也會產生唯一的識別碼做為您的 userId
變數。
使用您的專員的 ID 進行更新 <COPILOT ID>
。 您可以通過轉到 您正在使用的專員的 Channels (頻道) 選項卡 ,然後在門戶上 選擇 Mobile app Copilot Studio (移動應用程式)來查看您的專員的 ID。
<script>
(async function main() {
// Add your AGENT ID below
var BOT_ID = "<BOT ID>";
var theURL = "https://powerva.microsoft.com/api/botmanagement/v1/directline/directlinetoken?botId=" + BOT_ID;
const {
token
} = await fetchJSON(theURL);
var directline = await fetchJSON(regionalChannelSettingsURL).then(res=> res.channelUrlsById.directline);
const directLine = window.WebChat.createDirectLine({
domain: `${directline}v3/directline`,
token
});
var userID = clientApplication.account?.accountIdentifier != null ?
("Your-customized-prefix-max-20-characters" + clientApplication.account.accountIdentifier).substr(0, 64) :
(Math.random().toString() + Date.now().toString()).substr(0, 64); // Make sure this will not exceed 64 characters
const store = WebChat.createStore({}, ({
dispatch
}) => next => action => {
const {
type
} = action;
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'startConversation',
type: 'event',
value: {
text: "hello"
}
}
});
return next(action);
}
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const activity = action.payload.activity;
let resourceUri;
if (activity.from && activity.from.role === 'bot' &&
(resourceUri = getOAuthCardResourceUri(activity))) {
exchangeTokenAsync(resourceUri).then(function(token) {
if (token) {
directLine.postActivity({
type: 'invoke',
name: 'signin/tokenExchange',
value: {
id: activity.attachments[0].content.tokenExchangeResource.id,
connectionName: activity.attachments[0].content.connectionName,
token,
},
"from": {
id: userID,
name: clientApplication.account.name,
role: "user"
}
}).subscribe(
id => {
if (id === 'retry') {
// The agent was not able to handle the invoke, so display the oauthCard
return next(action);
}
// else: tokenexchange successful and we do not display the oauthCard
},
error => {
// an error occurred to display the oauthCard
return next(action);
}
);
return;
} else
return next(action);
});
} else
return next(action);
} else
return next(action);
});
const styleOptions = {
// Add styleOptions to customize Web Chat canvas
hideUploadButton: true
};
window.WebChat.renderWebChat({
directLine: directLine,
store,
userID: userID,
styleOptions
},
document.getElementById('webchat')
);
})().catch(err => console.error("An error occurred: " + err));
</script>
完整範例程式碼
如需更多資訊,您可以在我們的 GitHub 存放庫 找到完整的範例程式碼,以及 MSAL 及儲存條件指令碼。