Как добавить аутентификацию AD в моем чате чата - MS bot Framework v4 - PullRequest
1 голос
/ 15 апреля 2020

Я разрабатываю чат-бота с использованием MS bot Framework v4 SDK в C#.

Я выбрал Отправка образца бота в качестве своей базы, так как я использую QnA Создатель и Луис. Теперь я хочу добавить аутентификацию для доступа к моему боту. В соответствии с примером Authentication Bot Я добавил все зависимости, включая пакеты nuget, методы и классы, в код моего проекта бота, но все равно аутентификация у меня не работает, он выдает ошибку исключения и дает извините что-то пошло не так ошибка. Может быть некоторая проблема со способом интеграции и вызовом правильных методов.

, если у кого-либо есть решение или образец бота с аутентификацией и с использованием QnA Maker, пожалуйста, поделитесь со мной.

Мой код: Dispatchbot.cs

    namespace Microsoft.BotBuilderSamples
{

    public class DispatchBot<T> : ActivityHandler where T : Dialog
    {

        private ILogger _logger;
        private IBotServices _botServices;
        private BotState _conversationState;
        private BotState _userState;
        protected readonly Dialog Dialog;


        public DispatchBot(ConversationState conversationState, UserState userState, T dialog, ILogger<DispatchBot<T>> logger, IBotServices botServices)

        {
            _conversationState = conversationState;
            _userState = userState;
             Dialog = dialog;
            _logger = logger;
            _botServices = botServices;


        }

        [HttpGet]
        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            await Dialog.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
            /*....my custom logic..........*/

        }

        //added for authentication
        protected override async Task OnTokenResponseEventAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
        {
            _logger.LogInformation("Running dialog with Token Response Event Activity.");

            // Run the Dialog with the new Token Response Event Activity.
            await Dialog.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
        }

        //added code for welcome message on page load
        protected override async Task OnEventActivityAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
        {

          var oneventconversationStateAccessors = _conversationState.CreateProperty<oneventvalues>(nameof(oneventvalues));
          var onevntconversationData = await oneventconversationStateAccessors.GetAsync(turnContext, () => new oneventvalues());

            var objectdata = JsonConvert.DeserializeObject<dynamic>(turnContext.Activity.Value.ToString());

               data _data = new data();
               _data.prodselected = objectdata["Product"];
               _data.relselected = objectdata["Release"];
               _data.hour = objectdata["Hour"];

                /*....my custom logic..........*/


        }
        public class data
        {
            public string prodselected { get; set; }
            public string relselected { get; set; }
            public int hour { get; set; }


        }
        protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
            var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());

            foreach (var member in membersAdded)
            {
               if (member.Id != turnContext.Activity.Recipient.Id)
             {
                    userProfile.Name = member.Name.Replace('.', ' ');
                    await turnContext.SendActivityAsync(MessageFactory.Text($"Hi  **{member.Name.Replace('.',' ')}**. I'm your Assistant."), cancellationToken);
                    User = member.Name;
                }
            }

        }
        //added from statemanagement
        public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext?.Activity?.Type == ActivityTypes.Invoke && turnContext.Activity.ChannelId == "msteams")
                await Dialog.Run(turnContext, _conversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
            else
                await base.OnTurnAsync(turnContext, cancellationToken);

            // Save any state changes that might have occured during the turn.
            await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
            await _userState.SaveChangesAsync(turnContext, false, cancellationToken);

        }

        private async Task DispatchToTopIntentAsync(ITurnContext<IMessageActivity> turnContext, string intent, RecognizerResult recognizerResult, CancellationToken cancellationToken, ConversationData conversationData)
        {
            switch (intent)
            {
                case "q-qna-1":
                    await Process1(turnContext, cancellationToken,conversationData);
                    break;
                case "q-qna-2":

                    await Process2(turnContext, cancellationToken, conversationData);
                    break;
                default:
                    _logger.LogInformation($"Dispatch unrecognized intent: {intent}.");

            }
        }
               /*....my custom logic methods.........*/

        }

Authbot.cs

namespace Microsoft.BotBuilderSamples
{
    public class AuthBot<T> : DispatchBot<T> where T : Dialog
    {

        public AuthBot(ConversationState conversationState, UserState userState, ILogger<DispatchBot<T>> logger, T dialog, IBotServices botServices )
              : base(conversationState, userState, dialog, logger, botServices)
        {
        }

        protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            foreach (var member in turnContext.Activity.MembersAdded)
            {
                if (member.Id != turnContext.Activity.Recipient.Id)
                {
                    await turnContext.SendActivityAsync(MessageFactory.Text("Welcome to AuthenticationBot ."), cancellationToken);
                }
            }
        }

    }
}

MainDialog :

    namespace Microsoft.BotBuilderSamples
{
    public class MainDialog : LogoutDialog
    {
        protected readonly ILogger Logger;

        public MainDialog(IConfiguration configuration, ILogger<MainDialog> logger)
            : base(nameof(MainDialog), configuration["ConnectionName"])
        {
            Logger = logger;

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

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

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

            // 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)
        {
            // Get the token from the previous step. Note that we could also have gotten the
            // token directly from the prompt itself. There is an example of this in the next method.
            var tokenResponse = (TokenResponse)stepContext.Result;
            if (tokenResponse != null)
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("You are now logged in."), cancellationToken);
                return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = MessageFactory.Text("Would you like to view your token?") }, cancellationToken);
            }

            await stepContext.Context.SendActivityAsync(MessageFactory.Text("Login was not successful please try again."), cancellationToken);
            return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
        }

        private async Task<DialogTurnResult> DisplayTokenPhase1Async(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            await stepContext.Context.SendActivityAsync(MessageFactory.Text("Thank you."), cancellationToken);

            var result = (bool)stepContext.Result;
            if (result)
            {
                // Call the prompt again because we need the token. The reasons for this are:
                // 1. If the user is already logged in we do not need to store the token locally in the bot and worry
                // about refreshing it. We can always just call the prompt again to get the token.
                // 2. We never know how long it will take a user to respond. By the time the
                // user responds the token may have expired. The user would then be prompted to login again.
                //
                // There is no reason to store the token locally in the bot because we can always just call
                // the OAuth prompt to get the token or get a new token if needed.
                return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), cancellationToken: cancellationToken);
            }

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

        private async Task<DialogTurnResult> DisplayTokenPhase2Async(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var tokenResponse = (TokenResponse)stepContext.Result;
            if (tokenResponse != null)
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Here is your token {tokenResponse.Token}"), cancellationToken);
            }

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

Окончательное сообщение об ошибке в исключении:

невозможно получить идентификатор приложения бота из заявки на аудиторию.

1 Ответ

1 голос
/ 28 апреля 2020

Для запросов от канала идентификатор приложения указан в заявке аудитории на токен JWT. Ошибка «невозможно получить идентификатор приложения бота из заявки на аудиторию» вызвана тем, что он не может извлечь appID из состояния поворота и имеет нулевое значение. Вместо непосредственного добавления образца бота для аутентификации я бы порекомендовал следовать документации Add Authentication к боту , в которой содержатся пошаговые инструкции по добавлению кода в вашего бота. Вам будет легче сузиться, если вы пропустили какой-либо шаг. Я также предложил бы еще раз проверить, правильно ли настроено приложение Azure AD, и вы можете сгенерировать токен.

Надеюсь, это поможет.

...