ASP.NET Core 3.1 无法取消保护消息。状态在调试器中运行

Ola*_*avT 3 azure-active-directory asp.net-core

我已使用默认模板从 VS 2022 创建了 ASP.NET Core 3.1 Web 应用程序,并选择 Microsoft Identity 来使用 Azure AD 身份验证。向导在我的 Azure AD 租户中生成了应用程序注册,一切看起来都很好(回复 URL 等)

当我从调试器运行新生成的 Web 应用程序时,系统会提示我输入 Azure AD 凭据,然后重定向回我的应用程序并出现以下异常:

Exception: Unable to unprotect the message.State.

Unknown location
Exception: An error was encountered while handling the remote login.

Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()
Run Code Online (Sandbox Code Playgroud)

请注意,我没有添加或修改任何代码。它是 100% 由 VS2022 模板生成的。

Ruk*_*ini 8

  • 当您有多个 OIDC 中间件时,通常会出现“Exception: Unable to unprotect the message.State”错误。如果您有多个 OIDC,请检查是否需要为每个 OIDC 设置唯一的回调路径。
  • 将每个 OIDC 提供商的身份验证方案命名为oidc-demooidc-master
  • 返回状态参数时未正确解密,这可能是因为您的 OIDC 提供商之一正在尝试解密/取消保护另一个 OIDC 提供商的消息状态。
  • 尝试按照github讨论添加数据保护提供程序。

请检查以下链接以了解数据保护:

配置 ASP.NET Core 数据保护 | 微软文档

c# - Kubernetes 中的 Azure AD 身份验证无法取消对消息的保护。状态 - 代码日志

  • 确保redirectURI应该是您自己的控制器中的一个操作方法,如下所示:

            https://localhost:44381/test/callback 
    
    Run Code Online (Sandbox Code Playgroud)
  • 检查OnMessageReceived中的 UnProtect 方法以按照此链接中的讨论进行解密。

更详细的内容请参考以下链接:

asp.net core - 重定向到 IdentityServer4 中的客户端时出现错误代码 500“无法取消保护消息。状态” - 堆栈内存溢出

  • 我必须将 CallbackPath 从 `/signin-oidc` 更新为 `/signin-oidc-azure-ad` (或您想要的任何内容),然后也在 Azure -&gt; Azure AD -&gt; 应用程序注册 -&gt; 我的应用程序 -&gt; 身份验证中-&gt; Web - 重定向 URL 更新/添加 url 到 `https://localhost:12345/signin-oidc-azure-ad` (2认同)

dea*_*dog 8

我在使用 Azure AD 身份验证的普通 ASP.NET 6 模板时遇到了同样的问题,除了在本地一切正常,但当我将Unable to unprotect the message.State.其部署到 kubernetes 集群时收到错误。

对我来说,问题在于应用程序被部署到负载均衡器后面的多个实例,从而导致了问题。我在 GitHub 上遇到了这个问题,它向我推荐了这篇描述问题和解决方案的文章。

解决方案1

该文章建议使用可由所有正在运行的实例共享的集中数据存储来保存身份验证密钥,并使用与此类似的代码进行设置。

services.AddDataProtection()
    .SetApplicationName("MyApp")
    .SetDefaultKeyLifetime(TimeSpan.FromDays(30))
    .PersistKeysToAzureBlobStorage(new Uri("https://mystore.blob.core.windows.net/keyrings/master.xml"), new DefaultAzureCredential())
    .ProtectKeysWithAzureKeyVault(new Uri("https://myvault.vault.azure.net/keys/MasterEncryptionKey"), new DefaultAzureCredential());
Run Code Online (Sandbox Code Playgroud)

解决方案2

我的网络应用程序没有使用数据库,并且我不想引入一个数据库来进行身份验证,因此我将入口配置为使用 cookie 持久性。这意味着当发出请求时,响应包含一个 cookie,客户端将存储该 cookie 并将其包含在将来的请求中。cookie 告诉入口将请求定向到哪个实例,确保来自特定客户端的请求始终最终到达同一实例。

这可能并不适合所有场景,因为它可能会阻止负载均衡器在所有实例之间执行平等的请求分配。不过,在我的场景中,这种权衡很好,因为它不是大容量服务,而这就是我最终使用的解决方案。

这是我添加的 nginx ingress yaml 注释的示例:

services.AddDataProtection()
    .SetApplicationName("MyApp")
    .SetDefaultKeyLifetime(TimeSpan.FromDays(30))
    .PersistKeysToAzureBlobStorage(new Uri("https://mystore.blob.core.windows.net/keyrings/master.xml"), new DefaultAzureCredential())
    .ProtectKeysWithAzureKeyVault(new Uri("https://myvault.vault.azure.net/keys/MasterEncryptionKey"), new DefaultAzureCredential());
Run Code Online (Sandbox Code Playgroud)

您可以在其他产品中配置类似的 cookie 关联性规则,例如 F5 负载均衡器、Azure 应用程序网关等。

解决方案3

最后一个选项是仅托管服务的单个实例,在这种情况下,所有身份验证回调都将命中该单个服务。但这并不理想,因为这意味着您无法扩展 Web 应用程序以实现高可用性。


我不确定这与原始发布者在调试时在本地主机上收到此错误的问题有何关系。也许他们在本地计算机上运行了多个实例,或者在本地主机上运行了反向代理或拦截器(如 Fiddler),从而导致了问题?不管怎样,我想我应该为其他在搜索错误消息时偶然发现这个问题的人分享我的解决方案。