C# 如何用技巧实现虚拟助手Bot的OAuth提示认证

C# 如何用技巧实现虚拟助手Bot的OAuth提示认证,c#,azure,oauth-2.0,azure-active-directory,botframework,C#,Azure,Oauth 2.0,Azure Active Directory,Botframework,随后,我将身份验证添加到,作为通过创建的虚拟助手bot的一部分 我已经为该技能创建了Azure Active Directory V2应用程序注册,并在Azure门户中的技能机器人中添加了链接到该应用程序的OAuth连接。我还更新了技能的appsettings.json中的OAuthConnections appsettings.json "oauthConnections": [ { "name": "calendarconnection", "provid

随后,我将身份验证添加到,作为通过创建的虚拟助手bot的一部分

我已经为该技能创建了Azure Active Directory V2应用程序注册,并在Azure门户中的技能机器人中添加了链接到该应用程序的OAuth连接。我还更新了技能的appsettings.json中的OAuthConnections

appsettings.json

  "oauthConnections": [
    {
      "name": "calendarconnection",
      "provider": "Azure Active Directory v2"
    }
    . . .
但我一直在讨论如何实现OAuth提示流,以便用户从虚拟助手登录到技能,因为虚拟助手模板是以特定的方式构建的,即MainDialog继承自RouterDialog

public class MainDialog : RouterDialog
{
    public MainDialog(
            BotSettings settings,
            BotServices services,
            OnboardingDialog onboardingDialog,
            EscalateDialog escalateDialog,
            CancelDialog cancelDialog,
            List<SkillDialog> skillDialogs,
            IBotTelemetryClient telemetryClient,
            UserState userState)
            : base(nameof(MainDialog), telemetryClient)
    {
        . . .
    }

    . . .

    protected override async Task RouteAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
    {
        . . .
    }
    . . .
    protected override async Task<InterruptionAction> OnInterruptDialogAsync(DialogContext dc, CancellationToken cancellationToken)
    {
        . . .
    }
    . . .

Startup.cs

        public MainDialog(
            BotSettings settings,
            BotServices services,
            ResponseManager responseManager,
            ConversationState conversationState,
            UserState userState,
            ProactiveState proactiveState,
            CreateEventDialog createEventDialog,
            ChangeEventStatusDialog changeEventStatusDialog,
            TimeRemainingDialog timeRemainingDialog,
            SummaryDialog summaryDialog,
            UpdateEventDialog updateEventDialog,
            ConnectToMeetingDialog connectToMeetingDialog,
            UpcomingEventDialog upcomingEventDialog,
            LoginDialog loginDialog,               // added
            OAuthPrompt oAuthPrompt,               // added
            ConfirmPrompt confirmPrompt,           // added
            IBotTelemetryClient telemetryClient)
            : base(nameof(MainDialog), telemetryClient)
        {
            _settings = settings;
            _services = services;
            . . .

            AddDialog(loginDialog);
            AddDialog(oAuthPrompt);
            AddDialog(confirmPrompt);

        }
        . . .
        protected override async Task OnStartAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            await dc.BeginDialogAsync(nameof(LoginDialog));
            // send a greeting if we're in local mode
            await dc.Context.SendActivityAsync(_responseManager.GetResponse(CalendarMainResponses.CalendarWelcomeMessage));
        }
        . . .
public void ConfigureServices(IServiceCollection services)
{
 . . .
     services.AddTransient<LoginDialog>();
     services.AddTransient<OAuthPrompt>();
     services.AddScoped<ConfirmPrompt>(_ => new ConfirmPrompt(nameof(ConfirmPrompt)));
     services.AddScoped<OAuthPrompt>(_ => new OAuthPrompt(nameof(OAuthPrompt), new OAuthPromptSettings { ConnectionName = "calendarconnection", Title = "Sign In" }));
 . . .
}
public class LoginDialog : ComponentDialog
{
    public LoginDialog() 
        : base(nameof(LoginDialog))
    {
        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
        {
            PromptStepAsync,
            LoginStepAsync,
            DisplayTokenPhase1Async,
            DisplayTokenPhase2Async

         }));
    }

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

    {

        return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);

    }
    . . .
}
private async Task<List<Event>> GetMyCalendarViewByTime(DateTime startTime, DateTime endTime)
{
      . . .
      try
      {
           events = await _graphClient.Me.CalendarView.Request(options).GetAsync();
      }
      catch (ServiceException ex)
      {
           throw GraphClient.HandleGraphAPIException(ex);
      }
      . . .
}
public void配置服务(IServiceCollection服务)
{
. . .
services.AddTransient();
services.AddTransient();
AddScoped(=>newconfirmport(nameof(confirmport));
addScope(=>newOAuthPrompt(nameof(OAuthPrompt),newOAuthPromptSettings{ConnectionName=“calendarconnection”,Title=“Sign-In”}));
. . .
}
LoginDialog.cs

        public MainDialog(
            BotSettings settings,
            BotServices services,
            ResponseManager responseManager,
            ConversationState conversationState,
            UserState userState,
            ProactiveState proactiveState,
            CreateEventDialog createEventDialog,
            ChangeEventStatusDialog changeEventStatusDialog,
            TimeRemainingDialog timeRemainingDialog,
            SummaryDialog summaryDialog,
            UpdateEventDialog updateEventDialog,
            ConnectToMeetingDialog connectToMeetingDialog,
            UpcomingEventDialog upcomingEventDialog,
            LoginDialog loginDialog,               // added
            OAuthPrompt oAuthPrompt,               // added
            ConfirmPrompt confirmPrompt,           // added
            IBotTelemetryClient telemetryClient)
            : base(nameof(MainDialog), telemetryClient)
        {
            _settings = settings;
            _services = services;
            . . .

            AddDialog(loginDialog);
            AddDialog(oAuthPrompt);
            AddDialog(confirmPrompt);

        }
        . . .
        protected override async Task OnStartAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            await dc.BeginDialogAsync(nameof(LoginDialog));
            // send a greeting if we're in local mode
            await dc.Context.SendActivityAsync(_responseManager.GetResponse(CalendarMainResponses.CalendarWelcomeMessage));
        }
        . . .
public void ConfigureServices(IServiceCollection services)
{
 . . .
     services.AddTransient<LoginDialog>();
     services.AddTransient<OAuthPrompt>();
     services.AddScoped<ConfirmPrompt>(_ => new ConfirmPrompt(nameof(ConfirmPrompt)));
     services.AddScoped<OAuthPrompt>(_ => new OAuthPrompt(nameof(OAuthPrompt), new OAuthPromptSettings { ConnectionName = "calendarconnection", Title = "Sign In" }));
 . . .
}
public class LoginDialog : ComponentDialog
{
    public LoginDialog() 
        : base(nameof(LoginDialog))
    {
        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
        {
            PromptStepAsync,
            LoginStepAsync,
            DisplayTokenPhase1Async,
            DisplayTokenPhase2Async

         }));
    }

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

    {

        return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);

    }
    . . .
}
private async Task<List<Event>> GetMyCalendarViewByTime(DateTime startTime, DateTime endTime)
{
      . . .
      try
      {
           events = await _graphClient.Me.CalendarView.Request(options).GetAsync();
      }
      catch (ServiceException ex)
      {
           throw GraphClient.HandleGraphAPIException(ex);
      }
      . . .
}
public类LoginDialog:ComponentDialog
{
公共后勤
:base(name of(LoginDialog))
{
AddDialog(新建WaterWallDialog)(名称(WaterWallDialog),新建WaterWallStep[]
{
PromptStepAsync,
LoginStepAsync,
DisplayTokenPhase1Async,
DisplayTokenPhase2Async
}));
}
专用异步任务PromptStepAsync(WaterWallStepContext stepContext,CancellationToken CancellationToken)
{
返回wait-stepContext.BeginDialogAsync(nameof(OAuthPrompt),null,cancellationToken);
}
. . .
}
这里最大的问题是,在我已经登录后,仍有人要求我登录。还要注意的是,第三个OAuth提示符是不同的,这就是为什么我单击它时会出现以下错误。

代码:InvalidAuthenticationToken 消息:CompactToken解析失败,错误代码:80049217

内部误差

这是代码中发生异常的地方:

MSGraphCalendarAPI.cs

        public MainDialog(
            BotSettings settings,
            BotServices services,
            ResponseManager responseManager,
            ConversationState conversationState,
            UserState userState,
            ProactiveState proactiveState,
            CreateEventDialog createEventDialog,
            ChangeEventStatusDialog changeEventStatusDialog,
            TimeRemainingDialog timeRemainingDialog,
            SummaryDialog summaryDialog,
            UpdateEventDialog updateEventDialog,
            ConnectToMeetingDialog connectToMeetingDialog,
            UpcomingEventDialog upcomingEventDialog,
            LoginDialog loginDialog,               // added
            OAuthPrompt oAuthPrompt,               // added
            ConfirmPrompt confirmPrompt,           // added
            IBotTelemetryClient telemetryClient)
            : base(nameof(MainDialog), telemetryClient)
        {
            _settings = settings;
            _services = services;
            . . .

            AddDialog(loginDialog);
            AddDialog(oAuthPrompt);
            AddDialog(confirmPrompt);

        }
        . . .
        protected override async Task OnStartAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            await dc.BeginDialogAsync(nameof(LoginDialog));
            // send a greeting if we're in local mode
            await dc.Context.SendActivityAsync(_responseManager.GetResponse(CalendarMainResponses.CalendarWelcomeMessage));
        }
        . . .
public void ConfigureServices(IServiceCollection services)
{
 . . .
     services.AddTransient<LoginDialog>();
     services.AddTransient<OAuthPrompt>();
     services.AddScoped<ConfirmPrompt>(_ => new ConfirmPrompt(nameof(ConfirmPrompt)));
     services.AddScoped<OAuthPrompt>(_ => new OAuthPrompt(nameof(OAuthPrompt), new OAuthPromptSettings { ConnectionName = "calendarconnection", Title = "Sign In" }));
 . . .
}
public class LoginDialog : ComponentDialog
{
    public LoginDialog() 
        : base(nameof(LoginDialog))
    {
        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
        {
            PromptStepAsync,
            LoginStepAsync,
            DisplayTokenPhase1Async,
            DisplayTokenPhase2Async

         }));
    }

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

    {

        return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);

    }
    . . .
}
private async Task<List<Event>> GetMyCalendarViewByTime(DateTime startTime, DateTime endTime)
{
      . . .
      try
      {
           events = await _graphClient.Me.CalendarView.Request(options).GetAsync();
      }
      catch (ServiceException ex)
      {
           throw GraphClient.HandleGraphAPIException(ex);
      }
      . . .
}
private异步任务GetMyCalendarViewByTime(DateTime startTime,DateTime endTime)
{
. . .
尝试
{
events=await_graphClient.Me.CalendarView.Request(options).GetAsync();
}
捕获(ServiceException ex)
{
抛出GraphClient.HandleGraphApieException(ex);
}
. . .
}

你能在appsettings.json中发布你是如何配置oauthConnections的吗?我已经更新了帖子。oauthConnections看起来不错。你能发布你到目前为止尝试过的内容吗?我已经更新了我尝试过的内容。错误是从Microsoft Graph API返回的。我建议解析令牌,看看它是否有问题。你能试着在这里解析它吗?同时,我会看一看你的更新代码,然后再继续。