ASP.NET Core 2.1 Cookie身份验证似乎具有服务器相​​似性

aev*_*tas 5 c# openid-connect kubernetes auth0 asp.net-core

我正在ASP.NET Core 2.1中开发一个应用程序,并在Kubernetes群集上运行它。我已经使用Auth0作为提供者,使用OpenIDConnect实现了身份验证。

这一切都很好。标有该[Authorize]属性的操作或控制器将匿名用户重定向到身份提供者,他们登录,重定向回来,而Bob是您的叔叔。

当我将部署扩展到2个或更多容器时,就会开始出现问题。当用户访问应用程序时,他们将登录,并根据回调过程中为它们提供服务的容器,身份验证是成功还是失败。即使在身份验证成功的情况下,当用户点击未授权的容器时,反复进行F5-ing操作也会最终重定向到身份提供者。

我对此的思路是,使用cookie身份验证,用户将cookie存储在浏览器中,并随每个请求一起传递,应用程序对其进行解码并获取JWT,然后从中获取声明,然后用户已认证。这使整个事情变得无状态,因此,不管为请求提供服务的容器如何,它都应该工作。但是,如上所述,它似乎并没有以这种方式实际工作。

我的配置Startup.cs如下所示:

services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect("Auth0", options =>
    {
        options.Authority = $"https://{Configuration["Auth0:Domain"]}";

        options.ClientId = Configuration["Auth0:ClientId"];
        options.ClientSecret = Configuration["Auth0:ClientSecret"];

        options.ResponseType = "code";

        options.Scope.Clear();
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("email");

        options.TokenValidationParameters = new TokenValidationParameters
        {
            NameClaimType = "name"
        };

        options.SaveTokens = true;

        options.CallbackPath = new PathString("/signin-auth0");

        options.ClaimsIssuer = "Auth0";

        options.Events = new OpenIdConnectEvents
        {
            OnRedirectToIdentityProviderForSignOut = context =>
            {
                var logoutUri =
                    $"https://{Configuration["Auth0:Domain"]}/v2/logout?client_id={Configuration["Auth0:ClientId"]}";

                var postLogoutUri = context.Properties.RedirectUri;
                if (!string.IsNullOrEmpty(postLogoutUri))
                {
                    if (postLogoutUri.StartsWith("/"))
                    {
                        var request = context.Request;
                        postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase +
                                        postLogoutUri;
                    }

                    logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
                }

                context.Response.Redirect(logoutUri);
                context.HandleResponse();

                return Task.CompletedTask;
            },
            OnRedirectToIdentityProvider = context =>
            {
                context.ProtocolMessage.SetParameter("audience", "https://api.myapp.com");

                // Force the scheme to be HTTPS, otherwise we end up redirecting back to HTTP in production.
                // They should seriously make it easier to make Kestrel serve over TLS in the same way ngninx does...
                context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http://",
                    "https://", StringComparison.OrdinalIgnoreCase);

                Debug.WriteLine($"RedirectURI: {context.ProtocolMessage.RedirectUri}");

                return Task.FromResult(0);
            }
        };
    });
Run Code Online (Sandbox Code Playgroud)

我花了数小时试图解决这个问题,然后空了出来。从理论上讲,我现在唯一可以想到的就是使用粘性负载平衡,但这要比实际解决问题更多地应用创可贴。

使用Kubernetes的主要原因之一是其弹性和很好地处理扩展的能力。就目前而言,我只能扩展我的支持服务,而我的主应用程序必须作为一个单独的Pod运行。这远非理想。

也许某处存在某种机制,可以与我不知道的特定实例建立亲和力?

我希望有人能指出我正确的方向。

谢谢!

Chr*_*att 11

身份验证发出的 cookie 通过数据保护进行加密。默认情况下,数据保护范围仅限于特定应用程序或其实例。如果您需要在实例之间共享一个 auth cookie,您需要确保数据保护密钥持久保存到一个公共位置并且应用程序名称相同。

services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .SetApplicationName("MyApp");
Run Code Online (Sandbox Code Playgroud)

您可以在文档中找到更多信息。

  • @MatthewBrubaker:这就是所谓的“粘性会话”,它们是一种反模式。它部分抵消了拥有多个实例的好处,并完全终止了故障转移。 (4认同)
  • 更新了[文档](https://learn.microsoft.com/en-us/aspnet/core/security/cookie-sharing?view=aspnetcore-2.2#share-authentication-cookies-among-aspnet-core-apps 的链接) (4认同)

Mat*_*kan 5

每当我重新启动 Azure 应用服务 (PaaS) 并且用户的 cookie 不再有效时,我都会遇到同样的问题。我的应用程序使用 ASP.NET Core Identity 框架。

以下文档解释了将数据保护配置为跨多个应用程序实例甚至多个 Web 应用程序的各种方法:

https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview

我发现使用 blob 存储帐户是使其正常工作的最快方法:

var storageAccount = CloudStorageAccount.Parse(configuration["Configuration key to Azure storage connection string"]);
var client = storageAccount.CreateCloudBlobClient();
var container = client.GetContainerReference("key-container");

container.CreateIfNotExistsAsync().GetAwaiter().GetResult();

services.AddDataProtection()
    .SetApplicationName("Application Name")
    .PersistKeysToAzureBlobStorage(container, "keys.xml");
Run Code Online (Sandbox Code Playgroud)