如何在负载平衡环境中使用 Azure AD 配置 Blazor 服务器应用程序?

问题描述

我使用带有工作或学校帐户身份验证选项的 Visual Studio 模板创建了一个 Intranet Blazor 服务器应用程序。在我的本地机器上运行以及将应用程序发布到我们的开发环境时,一切都运行良好。但是,一旦我将应用程序移至我们的临时环境,应用程序有时会在 Azure 中对用户进行身份验证后崩溃。

在对问题进行故障排除后,我认为问题在于我们的本地暂存环境是负载平衡的(模仿生产)。我们的开发环境没有负载平衡。我认为发生的事情是,一旦在 Azure 中通过身份验证并重定向回应用程序,由于负载平衡器,用户并不总是登陆同一台服务器。这会破坏 Signal-R 电路并导致应用程序崩溃。这也解释了为什么错误随机的;每 10 次登录尝试中可能发生 2 次。为了测试这一点,我从应用程序中删除了 Azure AD 身份验证,并允许匿名访问每个页面。崩溃停止了。

我的问题是,是否有人知道使用 Azure AD 身份验证的 Blazor 服务器与本地负载平衡器一起工作的任何解决方法。我在整个网络上进行了搜索,发现的唯一解决方法是对 Azure Signal R 服务使用粘性会话。我们还没有在云上托管应用程序。如果我想在我的环境中使用带有身份验证的 Blazor,切换到 Blazor Webassembly 是唯一的选择吗?工作人员建议将应用程序切换为使用我们的本地 ADFS 服务器。但是,那不会遇到同样的问题吗?

作为参考,以下是在应用程序中设置 Azure 身份验证的 startup.cs ConfigureServices 方法中的代码

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
            .AddAzureAD(options => Configuration.Bind("AzureAd",options));


        services.AddControllersWithViews(options =>
        {
            var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
            

            options.Filters.Add(new Authorizefilter(policy));
        });

解决方法

我找到了解决方案,并在此处发布,以防其他人遇到类似问题。

事实证明问题不在于 SignalR 或任何特定于 Blazor Server 的内容。在负载均衡环境开启开发者异常页面后,看到报错是“Unable to unprotect the message.State”。在 Azure AD 对用户进行身份验证之前,应用程序状态由中间件加密。当 Azure AD 回发时,它包含加密状态,然后中间件在客户端对其进行解密。

解密所需的密钥存储在网络服务器上。在负载平衡环境中,如果您登陆的服务器与您开始的服务器不同,那么中间件将尝试使用错误的密钥解密状态。这当然会导致错误。

要解决此问题,您必须将密钥存储在文件共享等中心位置,而不是服务器本身。实施修复实际上很简单。在 startup.cs 的 ConfigureServices 中包含以下行:

services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));

如果愿意,也可以选择将密钥存储在 Azure 上。

Kevin Dockx 的这篇文章终于给了我答案:

Solving Correlation Failed: State Property Not Found Errors (OpenID Connect Middleware / ASP.NET Core)