在 Azure 应用服务上运行的 ASPNET 6 中,User.Identity.Name 为 null,因为声明使用了错误的名称

Clu*_*PS1 8 azure asp.net-identity asp.net-core blazor-server-side

将 Blazor 服务器应用程序项目从 dotnet 5 迁移到 dotnet 6 后,我遇到了一个奇怪的身份验证问题。

该应用程序使用本地用户名和密码进行身份验证。

在ConfigureServices()中,我们有

        services.AddDefaultIdentity<IdentityUser>
            (options =>
            {
                options.SignIn.RequireConfirmedAccount = true;
                // attempt to force name claim to "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" 
                options.ClaimsIdentity.UserNameClaimType = System.Security.Claims.ClaimTypes.Name;
            })
            .AddRoles<IdentityRole>()
            .AddUserManager<UserManager<IdentityUser>>()
            .AddRoleManager<AspNetRoleManager<IdentityRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>();
Run Code Online (Sandbox Code Playgroud)

现在,这在 .net 5 中运行良好,无论是在开发环境中,还是在 Azure 应用服务(windows / iis)中

升级到 .net 6 后,观察到以下情况:

  • 开发环境(使用“Project”启动):一切都像以前一样工作(包括身份验证)
  • 产品环境(Azure 应用服务):身份验证已损坏。当有人登录时,“Identity.IsAuthenticated”为 true,但“Identity.Name”为 null。

我将问题追溯到以下内容:

  • 在Dev中,声明如下:
    2022-05-17 12:46:54.190 +12:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier  = 7f041757-3aad-4221-971a-729598c1d81e
    2022-05-17 12:46:54.190 +12:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name  = superadmin@local
    2022-05-17 12:46:54.190 +12:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress  = someone@somewhere.com
    2022-05-17 12:46:54.190 +12:00 [INF] Claim AspNet.Identity.SecurityStamp  = OJLEYFWG4JE4ND5NRPTRT4JVCVEE2ANR
    2022-05-17 12:46:54.191 +12:00 [INF] Claim http://schemas.microsoft.com/ws/2008/06/identity/claims/role  = SuperAdmin
    2022-05-17 12:46:54.191 +12:00 [INF] Claim amr  = pwd
Run Code Online (Sandbox Code Playgroud)

但在Prod(Azure App services)中,声明如下

2022-05-17 01:16:12.467 +00:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier  = 7f041757-3aad-4221-971a-729598c1d81e
2022-05-17 01:16:12.468 +00:00 [INF] **Claim name  = superadmin@local**
2022-05-17 01:16:12.471 +00:00 [INF] Claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress  = someone@somewhere.com
2022-05-17 01:16:12.472 +00:00 [INF] Claim AspNet.Identity.SecurityStamp  = OJLEYFWG4JE4ND5NRPTRT4JVCVEE2ANR
2022-05-17 01:16:12.473 +00:00 [INF] Claim http://schemas.microsoft.com/ws/2008/06/identity/claims/role  = SuperAdmin
2022-05-17 01:16:12.475 +00:00 [INF] Claim http://schemas.microsoft.com/claims/authnmethodsreferences  = pwd
2022-05-17 01:16:12.477 +00:00 [INF] Claim nameid  = 7f041757-3aad-4221-971a-729598c1d81e
2022-05-17 01:16:12.478 +00:00 [INF] Claim email  = someone@somewhere.com
2022-05-17 01:16:12.480 +00:00 [INF] Claim role  = SuperAdmin
2022-05-17 01:16:12.481 +00:00 [INF] Claim amr  = pwd

Run Code Online (Sandbox Code Playgroud)

索赔http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name丢失。name相反,我们可以看到称为保留用户名值的声明。

我尝试强制应用程序使用正确的声明名称

     options.ClaimsIdentity.UserNameClaimType = System.Security.Claims.ClaimTypes.Name;

Run Code Online (Sandbox Code Playgroud)

但这没有用。它仍然使用错误的名称。

很确定这是一个简单的配置在某处丢失 - 如果有人可以指出它吗?

更新1

我更新了代码如下

if (IsProduction)
{
     options.ClaimsIdentity.UserNameClaimType =  'name';  
}
Run Code Online (Sandbox Code Playgroud)

这实际上有效并允许用户登录。Identity.IsAuthenticated == true 且 Identity.Name != null。万岁!... 但为什么??

此外,以下内容适用于 ASPNET 6 上的 DEV:

        [Inject]
        IHttpContextAccessor HCA { get; set; }

                if (HCA?.HttpContext?.User?.Claims?.Any() == true)
                {
                    foreach (var claim in HCA.HttpContext.User.Claims)
                    {
                        Logger.Log("HCA Type = {t} Value = {v}", claim.Type, claim.Value);
                    }
                }
Run Code Online (Sandbox Code Playgroud)

但在 Prod 中,在 Azure 应用服务上,检查HCA?.HttpContext?.User?.Claims?.Any() == true 失败。这意味着 HttpContext 中没有声明。这怎么可能???

我安装了 Azure Web App 的 ASP.NET core 6.0 (x64) 扩展。它安装得很好,但对身份验证错误没有影响。

更新2

我找到了问题的根源,但还没有找到解决方案。事实证明,Azure Signal R 搞砸了。

在 Startup.cs 中我有这样的代码:

            if (IsProduction)
            {
                services.AddSignalR().AddAzureSignalR(options =>
                {
                    options.ServerStickyMode = Microsoft.Azure.SignalR.ServerStickyMode.Required;
                });
            }
Run Code Online (Sandbox Code Playgroud)

如果我删除它,那么声明就会恢复正常,这意味着:

  • 名称声明现在http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
  • HttpContext 再次工作

但当然我失去了 Azure SignalR,这没什么好处。

更奇怪的是:我使用“本地身份验证”模板创建了一个新的 ASPNET 6 Blazor Server App 项目,并将其部署到 Azure App Services。现在,索赔行为略有不同:

  • 名称声明正确http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
  • 一个名为的新声明unique_name 被添加到 ClaimsPrincipal 中
  • HttpContext 已损坏。
状态 名称声明 HttpContext
升级ASPNET 5项目;没有 Azure 信号 R 好的 在职的
升级ASPNET 5项目;使用Azure Signal R 破碎的 破碎的
新的 ASPNET 6 项目;使用Azure Signal R 在职的 破碎的

所以,结果是:Azure SignalR 肯定搞砸了我的身份验证。但为什么?我该如何解决它?

更新3

因此,事实证明, 在使用 Azure Signal R 时,System.IdentityModel.Tokens.Jwt 的版本很重要。

在上面的实验中,

  • 升级后的 NET5>NET6 项目使用 System.IdentityModel.Tokens.Jwt 6.10.0.20330 (名称声明错误,unique_name 声明缺失)
  • Fresh NET 6 项目使用 System.IdentityModel.Tokens.Jwt 6.8.0.11012 (较低版本 - 奇怪的是) (名称声明 OK,unique_name 声明存在)

为了解决我的问题,我只需升级到最新的 System.IdentityModel.Tokens.Jwt 6.18,现在升级后的 NET5 项目的身份验证再次起作用。

要了解更多信息,请参阅github 问题

附言。感谢 Azure SignalR 团队为我指明了正确的方向

Aja*_*ose 3

解决方法:-

当将 .NET5 升级到 .NET6 项目时使用System.IdentityModel.Tokens.Jwt 6.10.0.20330(名称声明错误,unique_name 声明丢失)。

要解决此升级到最新版本的问题System.IdentityModel.Tokens.Jwt 6.18,升级后的.NET5项目的身份验证将再次起作用。

PS:- Asversion 6.10无法与 Azure Signal R 正常工作。

有关更多信息,请参阅此MICROSOFT 文档GitHub 问题