봇에 Single Sign-On 추가
적용 대상: SDK v4
이 문서에서는 봇에서 SSO(Single Sign-On) 기능을 사용하는 방법을 보여 줍니다. 이를 위해 이 기능은 루트 또는 부모 봇이라고도 하는 소비자 봇을 사용하여 기술 또는 자식 봇과 상호 작용합니다. 이 문서에서는 루트 봇 및 기술 봇이라는 용어를 사용합니다.
SSO 지원을 포함하는 경우 사용자는 ID 공급자를 사용하여 루트 봇에 로그인할 수 있으며 컨트롤이 기술에 전달되면 다시 로그인할 필요가 없습니다.
루트 봇과 스킬 봇은 각각 별도의 메모리와 상태를 가진 서로 다른 서버에서 실행되는 별도의 봇입니다. 기술에 대한 자세한 내용은 기술 개요 및 기술 구현을 참조하세요. 사용자 인증에 대한 자세한 내용은 Bot Framework 인증 기본 사항, 사용자 인증 및 봇에 인증 추가를 참조하세요.
Important
웹 채팅 Azure AI Bot Service 인증을 사용하는 경우 몇 가지 중요한 보안 고려 사항을 염두에 두어야 합니다. 자세한 내용은 REST 인증 문서의 보안 고려 사항 섹션을 참조하세요.
필수 조건
- Bot 기본 사항, 상태 관리 및 Single Sign-On에 대한 지식
- 대화 상자 라이브러리에 대한 지식 및 순차 대화 흐름을 구현하고 대화 상자를 다시 사용하는 방법
- Azure 및 OAuth 2.0 개발에 대한 지식
- .NET용 Visual Studio 2019 이상.
- C#의 간단한 기술 소비자 및 기술을 갖춘 SSO입니다.
샘플 정보
이 문서에서는 RootBot과 SkillBot이라는 두 개의 봇을 참조합니다. RootBot은 SkillBot에 활동을 전달합니다. 이러한 일반적인 기술 시나리오를 모델링합니다.
- 루트 봇은 하나 이상의 기술 봇을 호출합니다.
- 루트 및 기술 봇은 모두 봇에 인증 추가 문서에 설명된 기본 인증을 구현합니다.
- 사용자가 루트 봇에 로그인합니다.
- SSO가 이미 루트 봇에 로그인되어 있으므로 사용자 상호 작용을 다시 요구하지 않고 기술 봇에 로그인됩니다.
Bot Framework에서 인증을 처리하는 방법에 대한 개요는 사용자 인증을 참조하세요. SSO 백그라운드 정보는 Single Sign-On을 참조하세요.
RootBot은 SSO를 지원합니다. 사용자가 _SkillBot 다시 인증할 필요 없이 사용자를 대신하여 SkillBot과 통신합니다.
샘플의 각 프로젝트에 대해 다음이 필요합니다.
- Azure에서 봇 리소스를 등록하는 Microsoft Entra ID 애플리케이션입니다.
- 인증을 위한 Microsoft Entra ID ID 공급자 애플리케이션입니다.
참고 항목
현재 Microsoft Entra ID ID 공급자만 지원됩니다.
Azure RootBot 리소스 만들기
- 에 대한 Azure Portal에서 Azure 봇 리소스를 만듭니다
RootBot
. Azure 봇 리소스 만들기에 설명된 단계를 따릅니다. - 봇 등록 앱 ID와 클라이언트 암호를 복사하고 저장합니다.
RootBot에 대한 Microsoft Entra ID ID 만들기
Microsoft Entra ID는 OAuth2.0과 같은 업계 표준 프로토콜을 사용하여 사용자를 안전하게 로그인하는 애플리케이션을 빌드할 수 있는 클라우드 ID 서비스입니다.
Microsoft Entra ID를
RootBot
사용하여 사용자를 인증하는 ID 애플리케이션을 만듭니다. Microsoft Entra ID ID 공급자 만들기에 설명된 단계를 따릅니다.왼쪽 창에서 매니페스트를 선택합니다.
accessTokenAcceptedVersion
을 2로 설정합니다.저장을 선택합니다.
왼쪽 창에서 API 노출을 선택합니다.
오른쪽 창에서 범위 추가를 선택합니다.
맨 오른쪽 에서 범위 추가 섹션에서 저장을 선택하고 계속합니다.
표시된 창의 동의할 수 있는 사용자 아래에서 관리자와 사용자를 선택합니다.
나머지 필수 정보를 입력합니다.
범위 추가를 선택합니다.
범위 값을 복사하고 저장합니다.
RootBot에 대한 OAuth 연결 설정 만들기
봇 등록에서
RootBot
Microsoft Entra ID 연결을 만들고 Microsoft Entra ID 및 아래에 설명된 값에 설명된 대로 값을 입력합니다.토큰 교환 URL을 비워 둡니다.
범위 상자에 이전 단계에서 저장한
RootBot
범위 값을 입력합니다.참고 항목
범위에는 사용자가 처음에 루트 봇에 로그인하는 URL이 포함되고 토큰 교환 URL 은 비어 있습니다.
예를 들어 루트 봇 appid가 rootAppId이고 기술 봇 appid가 skillAppId라고 가정해 보겠습니다. 루트 봇의 범위는 사용자를 로그인하는 데 사용되는 api://rootAppId/customScope 모양입니다. 그런 다음 이 루트 봇의 범위는 SSO 중에 api://skillAppId/customscope 교환됩니다.
연결 이름을 복사하고 저장합니다.
Azure SkillBot 리소스 만들기
- 에 대한 Azure Portal에서 Azure 봇 리소스를 만듭니다
SkillBot
. Azure 봇 리소스 만들기에 설명된 단계를 따릅니다. - 봇 등록 앱 ID와 클라이언트 암호를 복사하고 저장합니다.
SkillBot에 대한 Microsoft Entra ID ID 만들기
Microsoft Entra ID는 OAuth2.0과 같은 업계 표준 프로토콜을 사용하여 사용자를 안전하게 로그인하는 애플리케이션을 빌드할 수 있는 클라우드 ID 서비스입니다.
Microsoft Entra ID를 사용하여 봇을
SkillBot
인증하는 ID 애플리케이션을 만듭니다. Microsoft Entra ID ID 공급자 만들기에 설명된 단계를 따릅니다.왼쪽 창에서 매니페스트를 선택합니다.
accessTokenAcceptedVersion
을 2로 설정합니다.저장을 선택합니다.
왼쪽 창에서 API 노출을 선택합니다.
오른쪽 창에서 범위 추가를 선택합니다.
맨 오른쪽 에서 범위 추가 섹션에서 저장을 선택하고 계속합니다.
표시된 창의 동의할 수 있는 사용자 아래에서 관리자와 사용자를 선택합니다.
나머지 필수 정보를 입력합니다.
범위 추가를 선택합니다.
범위 값을 복사하고 저장합니다.
클라이언트 애플리케이션 추가를 선택합니다. 맨 오른쪽 섹션의 클라이언트 ID 상자에 이전에 저장한 RootBot ID 앱 ID를 입력합니다. 등록 앱 ID가 아닌 RootBot ID를 사용해야 합니다.
참고 항목
클라이언트 애플리케이션의 경우 Azure AI Bot Service는 Microsoft Entra ID B2C ID 공급자를 사용한 Single Sing-On을 지원하지 않습니다.
권한 있는 범위에서 범위 값으로 확인란을 선택합니다.
애플리케이션 추가를 선택합니다.
왼쪽의 탐색 창에서 API 권한을 선택합니다. 앱에 대한 API 권한을 명시적으로 설정하는 것이 가장 좋습니다.
오른쪽 창에서 권한 추가를 선택합니다.
Microsoft API를 선택한 다음 Microsoft Graph를 선택합니다.
위임된 권한을 선택하고 필요한 사용 권한이 선택되어 있는지 확인합니다. 이 샘플에는 아래에 나열된 권한이 필요합니다.
참고 항목
ADMIN CONSENT REQUIRED로 표시된 모든 권한은 사용자와 테넌트 관리자가 모두 로그인해야 합니다.
- openid
- profile
- User.Read
- User.ReadBasic.All
권한 추가를 선택합니다.
SkillBot에 대한 OAuth 연결 설정 만들기
봇 등록에서
SkillBot
Microsoft Entra ID 연결을 만들고 Microsoft Entra ID 및 아래에 설명된 값에 설명된 대로 값을 입력합니다.토큰 교환 URL 상자에 이전 단계에서 저장한
SkillBot
범위 값을 입력합니다.범위 상자에 공백
profile
openid
User.ReadBasic.All
User.Read
으로 구분된 다음 값을 입력합니다.연결 이름을 복사하여 파일에 저장합니다.
연결 테스트
- 연결 항목을 선택하여 만든 연결을 엽니다.
- 서비스 공급자 연결 설정 창의 맨 위에서 연결 테스트를 선택합니다.
- 처음으로 앱이 요청하는 권한을 나열하는 새 브라우저 탭이 열리고 수락하라는 메시지가 표시됩니다.
- 수락을 선택합니다.
- 그러면 연결 이름> 성공 페이지로 테스트 연결<로 리디렉션됩니다.
자세한 내용은 개발자용 Microsoft Entra ID(v1.0) 개요 및 Microsoft ID 플랫폼(v2.0) 개요를 참조하세요. v1 및 v2 엔드포인트의 차이점에 대한 자세한 내용은 Microsoft ID 플랫폼(v2.0)으로 업데이트하는 이유를 참조하세요. 자세한 내용은 Microsoft ID 플랫폼(이전의 개발자용 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
를 사용하여 Microsoft Entra ID 등록RootBot
에 로그인할 수 있습니다. 로그인한 후 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 Emulator를 설치합니다. 에뮬레이터를 사용하여 디버그도 참조하세요.
봇 샘플 로그인이 작동하도록 에뮬레이터를 구성해야 합니다. 인증을 위해 에뮬레이터 구성에 표시된 것처럼 아래 단계를 사용합니다.
인증 메커니즘을 구성한 후에는 실제 봇 샘플 테스트를 수행할 수 있습니다.
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에 있습니다.에뮬레이터를 시작합니다.
봇에 연결할 때 등록 앱 ID 및 암호를 입력합니다
RootBot
.대화를 시작하려면 입력
hi
합니다.로그인을 입력 합니다.
RootBot
AAD 인증 카드에 로그인이 표시됩니다.로그인을 선택합니다. ‘URL 열기 확인’ 팝업 대화가 표시됩니다.
확인을 선택합니다. 로그인되고 토큰이
RootBot
표시됩니다.토큰을 입력 하여 토큰 을 다시 표시합니다.
이제 .와 통신할 준비가 되었습니다
SkillBot
. 로그인RootBot
한 후에는 로그아웃할 때까지 자격 증명을 다시 제공할 필요가 없습니다. 이는 SSO가 작동 중임을 보여 줍니다.에뮬레이터 상자에 기술 로그인을 입력합니다. 다시 로그인하라는 메시지가 표시되지 않습니다. 대신 SkillBot 토큰이 표시됩니다.
기술 토큰을 입력하여 토큰을 다시 표시합니다.
이제 skill logout을 입력하여
SkillBot
에서 로그아웃할 수 있습니다. 그런 다음 로그아웃을 입력하여 로그아웃합니다SimpleRootBoot
.
추가 정보
다음 시간 시퀀스 다이어그램은 문서에서 사용된 샘플에 적용되며 관련된 다양한 구성 요소 간의 상호 작용을 보여 줍니다. ABS는 Azure AI Bot Service를 의미합니다.
- 처음으로 사용자가 RootBot에
login
대한 명령을 입력합니다. - RootBot은 사용자에게 로그인을 요청하는 OAuthCard를 보냅니다.
- 사용자는 ABS(Azure AI Bot Service)로 전송되는 인증 자격 증명을 입력합니다.
- ABS는 사용자의 자격 증명을 기반으로 생성된 인증 토큰을 RootBot에 보냅니다.
- RootBot은 사용자가 볼 수 있는 루트 토큰을 표시합니다.
- 사용자가 SkillBot에
skill login
대한 명령을 입력합니다. - 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;
}