ボット アプリで SSO を有効にするコードを追加する

シングル サインオン (SSO) を有効にするコードを追加する前に、管理センターでアプリとボット リソースMicrosoft Entra構成済みであることを確認してください。

Microsoft Entra ID からアクセス トークンを取得するようにアプリのコードを構成する必要があります。 アクセス トークンは、ボット アプリに代わって発行されます。

注:

Microsoft Teams Toolkit を使用して Teams アプリを構築した場合は、「ツールと SDK」モジュールの手順に従って、アプリの SSO を有効にすることができます。 詳細については、「 Teams アプリにシングル サインオンを追加する」を参照してください。 Teams Toolkit では、Visual Studio Code および Teams Toolkit 17.4 Preview 3 for C# アプリの JavaScript アプリと TypeScript アプリの SSO がサポートされています。

このセクションでは、次の手順について説明します。

  1. 開発環境変数を更新する
  2. アクセス トークンを処理するコードを追加する
  3. トークンを受け取るコードを追加する
  4. アプリ ユーザーのログアウトを処理する

開発環境変数を更新する

アプリのクライアント シークレットと OAuth 接続設定を Microsoft Entra ID で構成しました。 これらの値を使用してコードを構成する必要があります。

開発環境変数を更新するには:

  1. ボット アプリ プロジェクトを開きます。

  2. プロジェクトの環境ファイルを開きます。

  3. 次の変数を更新します。

    • の場合MicrosoftAppIdは、ボット ID を Microsoft Entra ID から更新します。
    • の場合は MicrosoftAppPassword、クライアント シークレットを更新します。
    • の場合ConnectionNameは、Microsoft Entra ID で構成した OAuth 接続の名前を更新します。
    • の場合 MicrosoftAppTenantIdは、テナント ID を更新します。
  4. ファイルを保存します。

これで、ボット アプリと SSO に必要な環境変数が構成されました。 次に、ボット トークンを処理するためのコードを追加します。

アクセス トークンを処理するコードを追加する

トークンを取得する要求は、既存のメッセージ スキーマを使用した POST メッセージ要求です。 それは、OAuthCard の添付ファイルに含まれています。 OAuthCard クラスのスキーマは、 Microsoft Bot Schema 4.0 で定義されています。 プロパティがカードに設定されている場合TokenExchangeResource、Teams はトークンを更新します。 Microsoft Teams チャンネルの場合、トークンの要求を一意に認識するプロパティ Id だけが引き受けられます。

注:

Microsoft Bot Framework OAuthPrompt または MultiProviderAuthDialog は、SSO 認証でサポートされています。

アプリのコードを更新するには:

  1. のコード スニペットを追加します TeamsSSOTokenExchangeMiddleware

    次のコード スニペットを ( AdapterWithErrorHandler.cs またはアプリのコード内の同等のクラス) に追加します。

    base.Use(new TeamsSSOTokenExchangeMiddleware(storage, configuration["ConnectionName"]));
    

    注:

    ユーザーが複数のアクティブなエンドポイントを持っている場合、与えられた要求に対して複数の応答を受け取る場合があります。 トークンを使用して、重複または冗長な応答をすべて排除する必要があります。 signin/tokenExchange の詳細については、「 TeamsSSOTokenExchangeMiddleware クラス」を参照してください。

  2. トークンを要求するには、次のコード スニペットを使用します。

    を追加した後、 AdapterWithErrorHandler.cs次のコードが表示される必要があります。

        public class AdapterWithErrorHandler : CloudAdapter
        {
            public AdapterWithErrorHandler(
                IConfiguration configuration,
                IHttpClientFactory httpClientFactory,
                ILogger<IBotFrameworkHttpAdapter> logger,
                IStorage storage,
                ConversationState conversationState)
                : base(configuration, httpClientFactory, logger)
            {
                base.Use(new TeamsSSOTokenExchangeMiddleware(storage, configuration["ConnectionName"]));
    
                OnTurnError = async (turnContext, exception) =>
                {
                    // Log any leaked exception from the application.
                    // NOTE: In production environment, you must consider logging this to
                    // Azure Application Insights. Visit https://learn.microsoft.com/azure/bot-service/bot-builder-telemetry?view=azure-bot-service-4.0&tabs=csharp to see how
                    // to add telemetry capture to your bot.
                    logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
    
                    // Send a message to the user.
                    await turnContext.SendActivityAsync("The bot encountered an error or bug.");
                    await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code.");
    
                    if (conversationState != null)
                    {
                        try
                        {
                            // Delete the conversationState for the current conversation to prevent the
                            // bot from getting stuck in a error-loop caused by being in a bad state.
                            // conversationState must be thought of as similar to "cookie-state" in a Web pages.
                            await conversationState.DeleteAsync(turnContext);
                        }
                        catch (Exception e)
                        {
                            logger.LogError(e, $"Exception caught on attempting to Delete ConversationState : {e.Message}");
                        }
                    }
    
                    // Send a trace activity, which is displayed in the Bot Framework Emulator.
                    await turnContext.TraceActivityAsync(
                        "OnTurnError Trace",
                        exception.Message,
                        "https://www.botframework.com/schemas/error",
                        "TurnError");
                };
            }
        }
    

アプリ ユーザーが初めてアプリケーションを使用していて、ユーザーの同意が必要な場合は、次のダイアログ ボックスが表示されます。

ボット SSO の同意ダイアログ

ユーザーが [続行] を選択すると、次のいずれかのイベントが発生します。

  • ボット UI にサインイン ボタンがある場合は、ボットのサインイン フローがアクティブになります。 アプリ ユーザーの同意を必要とするアクセス許可を決定できます。 アプリに 以外 openidの Graph アクセス許可が必要な場合は、この方法を使用します。

  • OAuth カードにボットにサインイン ボタンがない場合は、最小限のアクセス許可セットにアプリ ユーザーの同意が必要です。 このトークンは、基本認証やアプリ ユーザーのメール アドレスの取得に役立ちます。

表示される同意ダイアログは、Microsoft Entra ID で定義された open-id スコープ用です。 アプリ ユーザーは同意を 1 回だけ行う必要があります。 同意した後、アプリ ユーザーは、付与されたアクセス許可とスコープに対してボット アプリにアクセスして使用できます。

注:

アプリ ユーザーが同意した後、他のアクセス許可に対してもう一度同意する必要はありません。 スコープで定義されているアクセス許可Microsoft Entra変更された場合、アプリ ユーザーはもう一度同意する必要があります。 ただし、同意プロンプトでアプリ ユーザーがアクセスできない場合、ボット アプリはサインインカードにフォールバックします。

重要

同意ダイアログが不要なシナリオ:

  • テナント管理者がテナントに代わって同意した場合、アプリ ユーザーに同意を求めるメッセージを表示する必要はありません。 つまり、アプリ ユーザーは同意ダイアログを表示せず、アプリにシームレスにアクセスできます。
  • Microsoft Entra アプリが Teams で認証を要求しているのと同じテナントに登録されている場合、アプリ ユーザーは同意を求められず、すぐにアクセス トークンが付与されます。 アプリ ユーザーは、Microsoft Entra アプリが別のテナントに登録されている場合にのみ、これらのアクセス許可に同意します。

エラーが発生した場合は、「 Teams での SSO 認証のトラブルシューティング」を参照してください。

トークンを受け取るコードを追加する

トークンを使用した応答は、ボットが今日受け取る他の呼び出しアクティビティと同じスキーマを持つ呼び出しアクティビティを介して送信されます。 唯一の違いは、呼び出し名、サインイン/tokenExchange、および フィールドです。 フィールドには、ID、トークンを取得するための最初の要求の文字列、トークン フィールド、トークンを含む文字列値が含まれます。

応答を呼び出すには、次のコード スニペットを使用します。

public MainDialog(IConfiguration configuration, ILogger<MainDialog> logger)
            : base(nameof(MainDialog), configuration["ConnectionName"])
        {
            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)
                    EndOnInvalidMessage = true
                }));

            AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));

            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                PromptStepAsync,
                LoginStepAsync,
            }));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }


private async Task<DialogTurnResult> PromptStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
        }

private async Task<DialogTurnResult> LoginStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {

            var tokenResponse = (TokenResponse)stepContext.Result;
            if (tokenResponse?.Token != null)
            {
                var token = tokenResponse.Token;

                // On successful login, the token contains sign in token.
            }
            else 
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("Login was not successful please try again."), cancellationToken);
            }            

            return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
        }

注:

コード スニペットでは、ウォーターフォール ダイアログが使用されます。 詳細については、「 コンポーネントとウォーターフォール ダイアログについて」を参照してください。

アクセス トークンを検証する

サーバー上の Web API は、アクセス トークンをデコードし、クライアントから送信されているかどうかを確認する必要があります。

注:

Bot Framework を使用すると、アクセス トークンの検証が処理されます。 Bot Framework を使用しない場合は、このセクションに記載されているガイドラインに従ってください。

アクセス トークンの検証の詳細については、「 トークンの検証」を参照してください。

JWT の検証を処理できるライブラリが複数入手可能です。 基本的な検証には、次のものが含まれます。

  • トークンが整形式であることを確認します。
  • トークンが目的の機関によって発行されたことを確認します。
  • トークンが Web API の対象であることを確認します。

トークンの検証時には、次のガイドラインに注意してください。

  • 有効な SSO トークンは、Microsoft Entra ID によって発行されます。 トークン内の要求は iss 、この値で始まる必要があります。
  • トークンのaud1パラメーターは、アプリの登録中に生成されたアプリ ID Microsoft Entra設定されます。
  • トークンの scp パラメーターは に access_as_user設定されます。

アクセス トークンの例

次のコード スニペットは、アクセス トークンの一般的なデコードされたペイロードです。

{
    aud: "2c3caa80-93f9-425e-8b85-0745f50c0d24",
    iss: "https://login.microsoftonline.com/fec4f964-8bc9-4fac-b972-1c1da35adbcd/v2.0",
    iat: 1521143967,
    nbf: 1521143967,
    exp: 1521147867,
    aio: "ATQAy/8GAAAA0agfnU4DTJUlEqGLisMtBk5q6z+6DB+sgiRjB/Ni73q83y0B86yBHU/WFJnlMQJ8",
    azp: "e4590ed6-62b3-5102-beff-bad2292ab01c",
    azpacr: "0",
    e_exp: 262800,
    name: "Mila Nikolova",
    oid: "6467882c-fdfd-4354-a1ed-4e13f064be25",
    preferred_username: "milan@contoso.com",
    scp: "access_as_user",
    sub: "XkjgWjdmaZ-_xDmhgN1BMP2vL2YOfeVxfPT_o8GRWaw",
    tid: "fec4f964-8bc9-4fac-b972-1c1da35adbcd",
    uti: "MICAQyhrH02ov54bCtIDAA",
    ver: "2.0"
}

アプリ ユーザーのログアウトを処理する

アプリ ユーザーがログアウトした場合にアクセス トークンを処理するには、次のコード スニペットを使用します。

    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();

                // Allow logout anywhere in the command.
                if (text.IndexOf("logout") >= 0)
                {
                    // 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;
        }

コード サンプル

サンプルの名前 説明 C# Node.js
ボット会話 SSO クイック スタート このサンプル コードは、Microsoft Teams 用ボットでの SSO の使用を開始する方法を示しています。 表示 表示

注:

OnTeamsMessagingExtensionQueryAsyncOnTeamsAppBasedLinkQueryAsyncTeamsMessagingExtensionsSearchAuthConfigBot.cs サポートされている唯一の SSO ハンドラーです。 その他の SSO ハンドラーはサポートされていません。

このセクションでは、次の手順について説明します。

  1. 開発環境変数を更新する
  2. トークンを要求するコードを追加する
  3. トークンを受け取るコードを追加する
  4. Bot Framework トークン ストアにトークンを追加する
  5. アプリ ユーザーのログアウトを処理する

開発環境変数を更新する

アプリのクライアント シークレットと OAuth 接続設定を Microsoft Entra ID で構成しました。 これらの変数を使用してアプリ コードを構成する必要があります。

開発環境変数を更新するには:

  1. アプリ プロジェクトを開きます。

  2. プロジェクトの ./env ファイルを開きます。

  3. 次の変数を更新します。

    • の場合MicrosoftAppIdは、ボット登録 ID を Microsoft Entra ID から更新します。
    • の場合 MicrosoftAppPasswordは、ボット登録クライアント シークレットを更新します。
    • の場合ConnectionNameは、Microsoft Entra ID で構成した OAuth 接続の名前を更新します。
    • の場合 MicrosoftAppTenantIdは、テナント ID を更新します。
  4. ファイルを保存します。

これで、ボット アプリと SSO に必要な環境変数が構成されました。 次に、トークンを処理するためのコードを追加します。

トークンを要求するコードを追加する

トークンを取得する要求は、既存のメッセージ スキーマを使用した POST メッセージ要求です。 それは、OAuthCard の添付ファイルに含まれています。 OAuthCard クラスのスキーマは、 Microsoft Bot Schema 4.0 で定義されています。 プロパティがカードに設定されている場合TokenExchangeResource、Teams はトークンを更新します。 Microsoft Teams チャンネルの場合、トークンの要求を一意に認識するプロパティ Id だけが引き受けられます。

注:

Microsoft Bot Framework OAuthPrompt または MultiProviderAuthDialog は、SSO 認証でサポートされています。

アプリのコードを更新するには:

  1. のコード スニペットを追加します TeamsSSOTokenExchangeMiddleware

    次のコード スニペットを ( AdapterWithErrorHandler.cs またはアプリのコード内の同等のクラス) に追加します。

    base.Use(new TeamsSSOTokenExchangeMiddleware(storage, configuration["ConnectionName"]));
    

    注:

    ユーザーが複数のアクティブなエンドポイントを持っている場合、与えられた要求に対して複数の応答を受け取る場合があります。 トークンを使用して、重複または冗長な応答をすべて排除する必要があります。 signin/tokenExchange の詳細については、「 TeamsSSOTokenExchangeMiddleware クラス」を参照してください。

  2. トークンを要求するには、次のコード スニペットを使用します。

    を追加した後、 AdapterWithErrorHandler.cs次のコードが表示される必要があります。

        public class AdapterWithErrorHandler : CloudAdapter
        {
            public AdapterWithErrorHandler(
                IConfiguration configuration,
                IHttpClientFactory httpClientFactory,
                ILogger<IBotFrameworkHttpAdapter> logger,
                IStorage storage,
                ConversationState conversationState)
                : base(configuration, httpClientFactory, logger)
            {
                base.Use(new TeamsSSOTokenExchangeMiddleware(storage, configuration["ConnectionName"]));
    
                OnTurnError = async (turnContext, exception) =>
                {
                    // Log any leaked exception from the application.
                    // NOTE: In production environment, you must consider logging this to
                    // Azure Application Insights. Visit https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-telemetry?view=azure-bot-service-4.0&tabs=csharp to see how
                    // to add telemetry capture to your bot.
                    logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
    
                    // Send a message to the user.
                    await turnContext.SendActivityAsync("The bot encountered an error or bug.");
                    await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code.");
    
                    if (conversationState != null)
                    {
                        try
                        {
                            // Delete the conversationState for the current conversation to prevent the
                            // bot from getting stuck in an error-loop caused by being in a bad state.
                            // ConversationState must be thought of as similar to "cookie-state" in a Web pages.
                            await conversationState.DeleteAsync(turnContext);
                        }
                        catch (Exception e)
                        {
                            logger.LogError(e, $"Exception caught on attempting to Delete ConversationState : {e.Message}");
                        }
                    }
    
                    // Send a trace activity, which will be displayed in the Bot Framework Emulator.
                    await turnContext.TraceActivityAsync(
                        "OnTurnError Trace",
                        exception.Message,
                        "https://www.botframework.com/schemas/error",
                        "TurnError");
                };
            }
        }
    

アプリ ユーザーが初めてアプリを使用する場合は、SSO 認証に同意する必要があります。

メッセージ拡張機能アプリの SSO 認証

アプリ ユーザーがユーザー名を選択すると、アクセス許可が付与され、アプリを使用できます。

メッセージ拡張機能アプリの SSO 認証が完了しました

表示される同意ダイアログは、Microsoft Entra ID で定義された open-id スコープ用です。 アプリ ユーザーは同意を 1 回だけ行う必要があります。 同意した後、アプリ ユーザーは、付与されたアクセス許可とスコープに対してメッセージ拡張機能アプリにアクセスして使用できます。

重要

同意ダイアログが不要なシナリオ:

  • テナント管理者がテナントに代わって同意した場合、アプリ ユーザーに同意を求めるメッセージを表示する必要はありません。 つまり、アプリ ユーザーは同意ダイアログを表示せず、アプリにシームレスにアクセスできます。

エラーが発生した場合は、「 Teams での SSO 認証のトラブルシューティング」を参照してください。

トークンを受け取るコードを追加する

トークンを使用した応答は、ボットが今日受け取る他の呼び出しアクティビティと同じスキーマを持つ呼び出しアクティビティを介して送信されます。 唯一の違いは、呼び出し名、サインイン/tokenExchange、および フィールドです。 フィールドには、ID、トークンを取得するための最初の要求の文字列、トークン フィールド、トークンを含む文字列値が含まれます。

応答を呼び出すには、次のコード スニペットの例を使用します。

public MainDialog(IConfiguration configuration, ILogger<MainDialog> logger)
            : base(nameof(MainDialog), configuration["ConnectionName"])
        {
            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)
                    EndOnInvalidMessage = true
                }));

            AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));

            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                PromptStepAsync,
                LoginStepAsync,
            }));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }


private async Task<DialogTurnResult> PromptStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
        }

private async Task<DialogTurnResult> LoginStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            
            var tokenResponse = (TokenResponse)stepContext.Result;
            if (tokenResponse?.Token != null)
            {
                var token = tokenResponse.Token;

                // On successful login, the token contains sign in token.
            }
            else 
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("Login was not successful please try again."), cancellationToken);
            }            

            return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
        }

注:

コード スニペットでは、ウォーターフォール ダイアログ ボットを使用します。 ウォーターフォール ダイアログの詳細については、「 コンポーネントダイアログとウォーターフォール ダイアログについて」を参照してください。

SSO を有効にするシナリオに応じて、ペイロードまたは で OnTeamsAppBasedLinkQueryAsyncハンドラーturnContext.Activity.ValueでトークンOnTeamsMessagingExtensionQueryAsyncを受け取ります。

JObject valueObject=JObject.FromObject(turnContext.Activity.Value);
if(valueObject["authentication"] !=null)
 {
    JObject authenticationObject=JObject.FromObject(valueObject["authentication"]);
    if(authenticationObject["token"] !=null)
 }

アクセス トークンを検証する

サーバー上の Web API は、アクセス トークンをデコードし、クライアントから送信されているかどうかを確認する必要があります。

注:

Bot Framework を使用すると、アクセス トークンの検証が処理されます。 Bot Framework を使用しない場合は、このセクションのガイドラインに従ってください。

アクセス トークンの検証の詳細については、「 トークンの検証」を参照してください。

JWT の検証を処理できるライブラリが複数入手可能です。 基本的な検証には、次のものが含まれます。

  • トークンが整形式であることを確認します。
  • トークンが目的の機関によって発行されたことを確認します。
  • トークンが Web API の対象であることを確認します。

トークンの検証時には、次のガイドラインに注意してください。

  • 有効な SSO トークンは、Microsoft Entra ID によって発行されます。 トークン内の要求は iss 、この値で始まる必要があります。
  • トークンのaud1パラメーターは、アプリの登録中に生成されたアプリ ID Microsoft Entra設定されます。
  • トークンの scp パラメーターは に access_as_user設定されます。

アクセス トークンの例

次のコード スニペットは、アクセス トークンの一般的なデコードされたペイロードです。

{
    aud: "2c3caa80-93f9-425e-8b85-0745f50c0d24",
    iss: "https://login.microsoftonline.com/fec4f964-8bc9-4fac-b972-1c1da35adbcd/v2.0",
    iat: 1521143967,
    nbf: 1521143967,
    exp: 1521147867,
    aio: "ATQAy/8GAAAA0agfnU4DTJUlEqGLisMtBk5q6z+6DB+sgiRjB/Ni73q83y0B86yBHU/WFJnlMQJ8",
    azp: "e4590ed6-62b3-5102-beff-bad2292ab01c",
    azpacr: "0",
    e_exp: 262800,
    name: "Mila Nikolova",
    oid: "6467882c-fdfd-4354-a1ed-4e13f064be25",
    preferred_username: "milan@contoso.com",
    scp: "access_as_user",
    sub: "XkjgWjdmaZ-_xDmhgN1BMP2vL2YOfeVxfPT_o8GRWaw",
    tid: "fec4f964-8bc9-4fac-b972-1c1da35adbcd",
    uti: "MICAQyhrH02ov54bCtIDAA",
    ver: "2.0"
}

Bot Framework トークン ストアにトークンを追加する

OAuth 接続を使用している場合は、Bot Framework トークン ストアでトークンを更新または追加する必要があります。 ストア内のトークンを更新または追加するために TeamsMessagingExtensionsSearchAuthConfigBot.cs 、次のコード スニペットの例を (またはアプリのコード内の同等のファイル) に追加します。

注:

サンプル TeamsMessagingExtensionsSearchAuthConfigBot.cs は、 Tab、Bot、Message Extension (ME) SSO にあります。

protected override async Task<InvokeResponse> OnInvokeActivityAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken)
     {
         JObject valueObject = JObject.FromObject(turnContext.Activity.Value);
         if (valueObject["authentication"] != null)
         {
             JObject authenticationObject = JObject.FromObject(valueObject["authentication"]);
             if (authenticationObject["token"] != null)
             {
                 //If the token is NOT exchangeable, then return 412 to require user consent.
                 if (await TokenIsExchangeable(turnContext, cancellationToken))
                 {
                     return await base.OnInvokeActivityAsync(turnContext, cancellationToken).ConfigureAwait(false);
                 }
                 else
                 {
                     var response = new InvokeResponse();
                     response.Status = 412;
                     return response;
                 }
             }
         }
         return await base.OnInvokeActivityAsync(turnContext, cancellationToken).ConfigureAwait(false);
     }
     private async Task<bool> TokenIsExchangeable(ITurnContext turnContext, CancellationToken cancellationToken)
     {
         TokenResponse tokenExchangeResponse = null;
         try
         {
             JObject valueObject = JObject.FromObject(turnContext.Activity.Value);
             var tokenExchangeRequest =
             ((JObject)valueObject["authentication"])?.ToObject<TokenExchangeInvokeRequest>();
             var userTokenClient = turnContext.TurnState.Get<UserTokenClient>();
             tokenExchangeResponse = await userTokenClient.ExchangeTokenAsync(
                             turnContext.Activity.From.Id,
                              _connectionName,
                              turnContext.Activity.ChannelId,
                              new TokenExchangeRequest
              {
                  Token = tokenExchangeRequest.Token,
              },
               cancellationToken).ConfigureAwait(false);
         }
 #pragma warning disable CA1031 //Do not catch general exception types (ignoring, see comment below)
         catch
 #pragma warning restore CA1031 //Do not catch general exception types
         {
             //ignore exceptions.
             //if token exchange failed for any reason, tokenExchangeResponse above remains null, and a failure invoke response is sent to the caller.
             //This ensures the caller knows that the invoke has failed.
         }
         if (tokenExchangeResponse == null || string.IsNullOrEmpty(tokenExchangeResponse.Token))
         {
             return false;
         }
         return true;
     }

アプリ ユーザーのログアウトを処理する

アプリ ユーザーがログアウトした場合にアクセス トークンを処理するには、次のコード スニペットを使用します。

    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();

                // Allow logout anywhere in the command.
                if (text.IndexOf("logout") >= 0)
                {
                    // 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;
        }

コード サンプル

このセクションでは、ボット認証 v3 SDK のサンプルを提供します。

サンプルの名前 説明 .NET Node.js Python マニフェスト
ボット認証 このサンプルでは、Teams 用ボットで認証を開始する方法を示します。 表示 表示 表示 表示
タブ、ボット、メッセージ拡張機能 (ME) SSO このサンプルでは、タブ、ボット、メッセージ拡張機能の SSO (検索、アクション、リンクの解除) を示します。 表示 表示 該当なし 表示
タブ、ボット、メッセージ拡張機能 このサンプルでは、SSO を使用してボット、タブ、メッセージ拡張機能で認証をチェックする方法を示します 表示 表示 該当なし 表示

次の手順