如何在我的聊天机器人中添加AD认证 - MS bot框架 v4

问题描述 投票:1回答:1

我正在使用MS bot framework v4 SDK在C#中开发一个聊天机器人。

我选择了 派遣机器人样本 作为我的基础,因为我正在使用QnA制造者和路易斯。现在我想添加一个认证来访问我的机器人。根据示例,我想添加一个认证来访问我的机器人。认证机器人 我已经在我的机器人项目代码中添加了所有的依赖关系,包括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.Cs

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

Final Error message in exception:

unable to get the bot AppId from the audience claim.

c# authentication botframework qnamaker
1个回答
1
投票

对于来自频道的请求,App Id在JWT token的Audience claim中。无法从观众声明中获取机器人App ID "的错误是因为它无法从turn状态中获取AppID,它是空的。与其直接添加认证机器人的样本,我建议按照 添加认证到机器人 文档,它提供了一步一步的说明,为你的机器人添加代码。这将使你很容易缩小范围,如果你错过了任何步骤。我还建议仔细检查Azure AD应用程序是否正确配置,以及您是否能够获得生成的令牌。

希望这能帮到你。

© www.soinside.com 2019 - 2024. All rights reserved.