ASP.NET Core 2.1 cookie-аутентификация имеет сходство с сервером - PullRequest
0 голосов
/ 27 ноября 2018

Я разрабатываю приложение в ASP.NET Core 2.1 и запускаю его в кластере Kubernetes.Я реализовал аутентификацию, используя OpenIDConnect, используя Auth0 в качестве моего провайдера.

Это все работает нормально.Действия или контроллеры, помеченные атрибутом [Authorize], перенаправляют анонимного пользователя на провайдера идентификации, они входят в систему, перенаправляют обратно, и Боб - твой дядя.

Проблемы начинают возникать, когда я масштабирую свое развертывание до 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);
            }
        };
    });

Я часами пытался решить эту проблему и вышел пустым.Единственное, что я могу думать о том, что сейчас это может теоретически сработать, - это использование балансировки нагрузки, но это скорее применение пластыря, чем собственно решение проблемы.

Одной из основных причин использования Kubernetes является его устойчивость испособность очень хорошо справляться с масштабированием.В существующем состоянии я могу масштабировать только свои вспомогательные службы, и мое основное приложение должно работать как один модуль.Это далеко от идеала.

Возможно, где-то есть механизм, который создает сходство с конкретным экземпляром, о котором я не знаю?

Надеюсь, кто-то может указать мне правильное направление.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 17 апреля 2019

Я сталкивался с той же проблемой, когда перезапускал службу приложений Azure (PaaS), и файлы cookie моих пользователей больше не действовали.Мое приложение использовало платформу ASP.NET Core Identity.

Ниже приведена документация, объясняющая различные способы настройки защиты данных для нескольких экземпляров приложения или даже нескольких веб-приложений:

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

Я обнаружил, что использование учетной записи для хранения больших двоичных объектов - самый быстрый способ заставить ее работать:

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");
0 голосов
/ 27 ноября 2018

Файл cookie, выданный при аутентификации, зашифрован с помощью функции защиты данных.Защита данных по умолчанию распространяется на конкретное приложение или его экземпляр.Если вам нужно совместно использовать файл cookie для проверки подлинности между экземплярами, необходимо убедиться, что ключи защиты данных сохранены в общем расположении и совпадает имя приложения.

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

Дополнительную информацию можно найти в документы .

...