Поделиться через


Добавление кода для включения единого входа в приложение бота

Перед добавлением кода для включения единого входа убедитесь, что вы настроили ресурс приложения и бота в Центре администрирования Microsoft Entra.

Необходимо настроить код приложения, чтобы получить маркер доступа из идентификатора Microsoft Entra. Маркер доступа выдается от имени приложения бота.

Примечание.

Если вы создали приложение Teams с помощью Microsoft Teams Toolkit, вы можете включить единый вход для приложения, следуя инструкциям в модуле Инструменты и пакеты SDK. Дополнительные сведения см. в статье Добавление единого входа в приложение Teams. Teams Toolkit поддерживает единый вход для приложений JavaScript и TypeScript в Visual Studio Code, а также в Наборе средств Teams 17.4, предварительная версия 3 для приложений C#.

Содержание раздела:

  1. Обновление переменных среды разработки
  2. Добавление кода для обработки маркера доступа
  3. Добавление кода для получения маркера
  4. Обработка выхода пользователя приложения

Обновление переменных среды разработки

Вы настроили секрет клиента и параметр подключения OAuth для приложения в идентификаторе Microsoft Entra. Необходимо настроить код с этими значениями.

Чтобы обновить переменные среды разработки, выполните следующие действия.

  1. Откройте проект приложения бота.

  2. Откройте файл среды для проекта.

  3. Обновите следующие переменные:

    • Для MicrosoftAppIdобновите идентификатор бота из Microsoft Entra ID.
    • Для MicrosoftAppPasswordобновите секрет клиента.
    • Для ConnectionNameобновите имя подключения OAuth, настроенного в идентификаторе Microsoft Entra.
    • Для MicrosoftAppTenantIdобновите идентификатор клиента.
  4. Сохраните файл.

Теперь вы настроили необходимые переменные среды для приложения бота и единого входа. Затем добавьте код для обработки маркеров бота.

Добавление кода для обработки маркера доступа

Запрос на получение маркера является запросом сообщения POST с использованием существующей схемы сообщения. Она включена во вложения OAuthCard. Схема для класса OAuthCard определена в схеме Microsoft Bot 4.0. Teams обновляет маркер, TokenExchangeResource если свойство заполнено на карточке. Для каналов Microsoft Teams учитывается только свойство Id, однозначно определяющее запрос маркера.

Примечание.

Microsoft Bot Framework OAuthPrompt или MultiProviderAuthDialog поддерживает проверку подлинности для единого входа.

Чтобы обновить код приложения, выполните приведенные ниже действия.

  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");
                };
            }
        }
    

Если пользователь приложения использует приложение в первый раз и требуется согласие пользователя, появится следующее диалоговое окно:

Диалоговое окно согласия для единого входа бота

Когда пользователь нажимает кнопку Продолжить, происходит одно из следующих событий:

  • Если в пользовательском интерфейсе бота есть кнопка входа, активируется поток входа для ботов. Вы можете определить разрешения, требующие согласия пользователя приложения. Используйте этот подход, если приложению требуются разрешения Graph, отличные от openid.

  • Если у бота нет кнопки входа на карточке OAuth, для минимального набора разрешений требуется согласие пользователя приложения. Этот маркер полезен для обычной проверки подлинности и получения адреса электронной почты пользователя приложения.

Появится диалоговое окно согласия для областей с открытым идентификатором, определенных в идентификаторе Microsoft Entra. Пользователь приложения должен дать согласие только один раз. После получения согласия пользователь приложения может получить доступ к приложению бота и использовать его для предоставленных разрешений и областей.

Примечание.

После того как пользователь приложения даст согласие, он не обязан повторно давать согласие на любые другие разрешения. Если разрешения, определенные в области Microsoft Entra, изменяются, пользователю приложения может потребоваться еще раз предоставить согласие. Однако если в запросе на согласие не удается предоставить пользователю приложения доступ, приложение бота вернется к карточке входа.

Важно!

Сценарии, в которых диалоги согласия не нужны:

  • Если администратор клиента предоставил согласие от имени клиента, пользователям приложений вообще не нужно запрашивать согласие. Это означает, что пользователи приложения не видят диалоговые окна согласия и могут легко получить доступ к приложению.
  • Если приложение Microsoft Entra зарегистрировано в том же клиенте, из которого вы запрашиваете проверку подлинности в Teams, пользователь приложения не может получить согласие и сразу же получает маркер доступа. Пользователи приложений соглашаться на эти разрешения, только если приложение Microsoft Entra зарегистрировано в другом клиенте.

При возникновении каких-либо ошибок см. статью Устранение неполадок с проверкой подлинности единого входа в Teams.

Добавление кода для получения маркера

Ответ с маркером отправляется с помощью действия вызова по той же схеме, что и другие действия вызова, получаемые ботами сегодня. Единственным отличием является имя вызова, вход/tokenExchange и поле значения . Поле значение содержит идентификатор, строку исходного запроса на получение маркера и поле маркер, строковое значение, содержащее маркер.

Используйте следующий фрагмент кода для вызова ответа:

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

Примечание.

Фрагменты кода используют каскадный диалог. Дополнительные сведения см. в разделе Сведения о диалоговых окнах компонента и каскада.

Проверка маркера доступа

Веб-API на сервере должны декодировать маркер доступа и проверять, отправлен ли он от клиента.

Примечание.

Если вы используете Bot Framework, она обрабатывает проверку маркера доступа. Если вы не используете Bot Framework, следуйте рекомендациям, приведенным в этом разделе.

Дополнительные сведения о проверке маркера доступа см. в разделе Проверка маркеров.

Доступно множество библиотек, которые могут выполнять проверку JWT. Базовая проверка включает в себя:

  • Проверка правильности форм маркера.
  • Проверка того, был ли маркер выдан предполагаемым центром.
  • Проверка того, что маркер предназначен для веб-API.

При проверке маркера учитывайте приведенные ниже рекомендации.

  • Допустимые маркеры единого входа выдаются идентификатором Microsoft Entra. Утверждение iss в маркере должно начинаться с этого значения.
  • Для параметра маркера aud1 задается идентификатор приложения, созданный во время регистрации приложения 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
Краткое руководство по единому входу в bot conversation В этом примере кода показано, как приступить к работе с единым входом в боте для Microsoft Teams. Просмотр Просмотр

Примечание.

OnTeamsMessagingExtensionQueryAsync и OnTeamsAppBasedLinkQueryAsync из TeamsMessagingExtensionsSearchAuthConfigBot.cs файла являются единственными поддерживаемыми обработчиками единого входа. Другие обработчики единого входа не поддерживаются.

Содержание раздела:

  1. Обновление переменных среды разработки
  2. Добавление кода для запроса маркера
  3. Добавление кода для получения маркера
  4. Добавление маркера в хранилище токенов Bot Framework
  5. Обработка выхода пользователя приложения

Обновление переменных среды разработки

Вы настроили секрет клиента и параметр подключения OAuth для приложения в идентификаторе Microsoft Entra. Необходимо настроить код приложения с помощью этих переменных.

Чтобы обновить переменные среды разработки, выполните следующие действия.

  1. Откройте проект приложения.

  2. ./env Откройте файл для проекта.

  3. Обновите следующие переменные:

    • Для MicrosoftAppIdобновите идентификатор регистрации бота из Microsoft Entra ID.
    • Для MicrosoftAppPasswordобновите секрет клиента регистрации бота.
    • Для ConnectionNameобновите имя подключения OAuth, настроенного в идентификаторе Microsoft Entra.
    • Для MicrosoftAppTenantIdобновите идентификатор клиента.
  4. Сохраните файл.

Теперь вы настроили необходимые переменные среды для приложения бота и единого входа. Затем добавьте код для обработки маркеров.

Добавление кода для запроса маркера

Запрос на получение маркера является запросом сообщения POST с использованием существующей схемы сообщения. Она включена во вложения OAuthCard. Схема для класса OAuthCard определена в схеме Microsoft Bot 4.0. Teams обновляет маркер, TokenExchangeResource если свойство заполнено на карточке. Для каналов Microsoft Teams учитывается только свойство Id, однозначно определяющее запрос маркера.

Примечание.

Microsoft Bot Framework OAuthPrompt или MultiProviderAuthDialog поддерживает проверку подлинности для единого входа.

Чтобы обновить код приложения, выполните приведенные ниже действия.

  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");
                };
            }
        }
    

Если пользователь приложения использует приложение в первый раз, он должен предоставить согласие на проверку подлинности единого входа.

Проверка подлинности единого входа для приложения расширения сообщений

Когда пользователь приложения выбирает имя пользователя, разрешение предоставляется, и он может использовать приложение.

Проверка подлинности единого входа завершена для приложения расширения сообщений

Появится диалоговое окно согласия для областей с открытым идентификатором, определенных в идентификаторе Microsoft Entra. Пользователь приложения должен дать согласие только один раз. После получения согласия пользователь приложения может получить доступ к приложению расширения сообщений и использовать его для предоставленных разрешений и областей.

Важно!

Сценарии, в которых диалоги согласия не нужны:

  • Если администратор клиента предоставил согласие от имени клиента, пользователям приложений вообще не нужно запрашивать согласие. Это означает, что пользователи приложения не видят диалоговые окна согласия и могут легко получить доступ к приложению.

При возникновении каких-либо ошибок см. статью Устранение неполадок с проверкой подлинности единого входа в Teams.

Добавление кода для получения маркера

Ответ с маркером отправляется с помощью действия вызова по той же схеме, что и другие действия вызова, получаемые ботами сегодня. Единственным отличием является имя вызова, вход/tokenExchange и поле значения . Поле значение содержит идентификатор, строку исходного запроса на получение маркера и поле маркер, строковое значение, содержащее маркер.

Используйте следующий пример фрагмента кода для вызова ответа:

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

Примечание.

Фрагменты кода используют бот Каскадного диалога. Дополнительные сведения о каскадном диалоге см. в разделе Сведения о диалоговых окнах компонента и каскадных диалогов.

Вы получаете маркер в OnTeamsMessagingExtensionQueryAsync обработчике в полезных turnContext.Activity.Value данных или в , в OnTeamsAppBasedLinkQueryAsyncзависимости от того, для какого сценария вы включаете единый вход.

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

Проверка маркера доступа

Веб-API на сервере должны декодировать маркер доступа и проверять, отправлен ли он от клиента.

Примечание.

Если вы используете Bot Framework, она обрабатывает проверку маркера доступа. Если вы не используете Bot Framework, следуйте рекомендациям, приведенным в этом разделе.

Дополнительные сведения о проверке маркера доступа см. в разделе Проверка маркеров.

Доступно множество библиотек, которые могут выполнять проверку JWT. Базовая проверка включает в себя:

  • Проверка правильности форм маркера.
  • Проверка того, был ли маркер выдан предполагаемым центром.
  • Проверка того, что маркер предназначен для веб-API.

При проверке маркера учитывайте приведенные ниже рекомендации.

  • Допустимые маркеры единого входа выдаются идентификатором Microsoft Entra. Утверждение iss в маркере должно начинаться с этого значения.
  • Для параметра маркера aud1 задается идентификатор приложения, созданный во время регистрации приложения 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).

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;
        }

Пример кода

В этом разделе приведен пример пакета SDK для проверки подлинности бота версии 3.

Название примера Описание .NET Node.js Python Манифест
Проверка подлинности бота В этом примере показано, как приступить к проверке подлинности в боте для Teams. Просмотр Просмотр Просмотр Просмотр
Единый вход в tab, bot и message extension (ME) В этом примере показан единый вход для табуляции, бота и расширения сообщений: поиск, действие, разворот ссылки. Просмотр Просмотр Н/Д Просмотр
Вкладка, бот и расширение сообщений В этом примере показано, как проверить проверку подлинности в боте, вкладке и расширении сообщений с помощью единого входа. Просмотр Просмотр Н/Д Просмотр

Следующий этап