Search code examples
c#azure-storagebotframework

Logged in user's context being used in a new conversation too while using botauth with Azure table storage


I am using BotAuth to login users on my bot. Recently I implemented Azure Table storage to store and manage bot’s state data, by following the steps mentioned in https://learn.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-state-azure-table-storage.

My Global.asax.cs file looks like this :

protected void Application_Start(object sender, EventArgs e)
    {
        {
            var config = GlobalConfiguration.Configuration;
            Conversation.UpdateContainer(
                builder =>
                {
                    builder.RegisterModule(new AzureModule(Assembly.GetExecutingAssembly()));

                    var store = new TableBotDataStore(ConfigurationManager.AppSettings["StorageConnectionString"], "botfactoryestimatorstate");
                    builder.Register(c => store)
                        .Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
                        .AsSelf()
                        .SingleInstance();

                    builder.Register(c => new CachingBotDataStore(store,
                                 CachingBotDataStoreConsistencyPolicy.ETagBasedConsistency))
                         .As<IBotDataStore<BotData>>()
                         .AsSelf()
                         .InstancePerLifetimeScope();
                    // Register your Web API controllers.
                    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
                    builder.RegisterWebApiFilterProvider(config);

                });

            config.DependencyResolver = new AutofacWebApiDependencyResolver(Conversation.Container);
        }

        // WebApiConfig stuff
        GlobalConfiguration.Configure(config =>
        {
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        });
    }

And MessagesController is same as the one in the bot template, no changes there.

On testing it in 2 emulator windows, one after the other, I notice that the first emulator prompts for login, while the other emulator window is taking in the context automatically, and not prompting in for authentication : enter image description here

On Debugging it, I found that context.UserData.TryGetValue($"{this.authProvider.Name}{ContextConstants.AuthResultKey}", out authResult) code in botauth returns values always, after any user is authenticated.

But when I change from the state management in azure table to use the old state management by bot framework, I get the expected behavior. enter image description here

What exactly am I missing? Is it some autofac module registration. Does anyone have a perfectly working sample for this.


Solution

  • This is due to the fact that each instance of the emulator hosts its own state service. When using a custom state client, the state is shared across all clients connecting (the emulator's state service is not used). If the id of the user is the same (as it is across different emulator instances), a shared state retrieves the same UserData (as it should).

    Note: this will not be an issue on channels other than the emulator and webchat, because the user's id is different. This can be overcome in webchat by generating a unique UserId whenever BotChat is initiated:

    <script>
          var uniqueUserId = getUniqueUserId();
          BotChat.App({
            directLine: { secret: direct_line_secret },
            user: { id: uniqueUserId  },
            bot: { id: 'botid' },
            resize: 'detect'
          }, document.getElementById("bot"));
    </script>
    

    https://github.com/MicrosoftDX/botauth/commit/b6e9751eab8d9b3bc02274882e4042ba788f4dca has not been released to nuget yet. The default state client is always retrieved in the CallbackController of the current botauth. Context dialogs retrieve the autofac state client implementation. This inconsistency is what the above commit fixes. It should be released to nuget soon.