Нопкоммерц Окта Интеграция - PullRequest
2 голосов
/ 21 января 2020

У меня есть следующее:

  • Управление идентификацией Okta с настраиваемым сервером авторизации
  • . net основное веб-приложение
  • . net основное веб API-приложение
  • Веб-приложение NopCommerce 4.2

Все они работают в Azure службах приложений. Веб-приложение и API-приложение, которое я создал, прекрасно работают вместе. Веб-приложение передает маркер носителя аутентификации в API, и API проверяет его с помощью промежуточного программного обеспечения Aspnetcore.Okta.

Тем не менее, теперь мне нужно вывести мое приложение Nopcommerce в сгибы. Я потратил 3 дня, пытаясь создать плагин - даже тот, который в принципе ничего не делает, и у меня не было ничего, кроме проблем. Я использовал их «официальный» шаблон, и у него есть свои проблемы. Поэтому я решил просто взять плагин для внешней аутентификации Facebook и начать его редактирование. По крайней мере, теперь у меня есть кое-что, с чем я действительно могу работать.

Вот где я действительно застрял ... Могу ли я просто вставить промежуточное ПО Okta и покончить с этим? Под этим я подразумеваю следующие шаги:

  1. Добавить контроллер действия входа для переопределения действия по умолчанию для входа в систему Nopcommerce
  2. Если пользователь не аутентифицирован, введите Challenge
  3. Middleware. это и перенаправление на страницу входа (в моем существующем веб-приложении)
  4. Пользователь регистрируется там
  5. Промежуточное программное обеспечение устанавливает сессионный повар ie и перенаправляет пользователя обратно в приложение Nopcomm
  6. Теперь, снова в Nopcomm, промежуточное программное обеспечение снова включается, видит повара ie, вызывает конечную точку / verify и затем заполняет ClaimsPrincipal для связанного пользователя.

Я думаю, что если ключи машин одинаковы в обоих приложениях, повар ie должен работать нормально.

Считаете ли вы, что это лучший подход, или я должен вместо этого следовать тем же шагам в 1-4, кроме как после 4, отправить пользователя обратно на сайт Nopcomm с токеном в строке запроса, а затем вручную проверить его на стороне Nopcomm?

1 Ответ

2 голосов
/ 23 января 2020

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

Первое, что я узнал, это то, что вы должны указать c в отношении типов задач, с которыми сталкиваются ваши приложения. , Если вы самостоятельно размещаете страницу входа в систему, вам нужно использовать:

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })

Если вы используете страницу входа Okta (или другого провайдера openId), вам необходимо выполнить другой тип вызова:

            builder.Services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })

Что я узнал, так это то, что если вы используете OpenID Connect в ASP. NET Базовом приложении и вы самостоятельно размещаете страницу входа, поток выглядит примерно так:

  1. Пользователь пытается получить доступ к защищенному ресурсу
  2. Маркер [Authorize] сообщает промежуточному программному обеспечению Okta о необходимости внедрить себя и выполнить свою задачу. User.Identity.IsAuthenticated имеет значение false, поэтому он перенаправляет на все, что установлено в параметрах cook ie в качестве пути входа в систему:
            .AddCookie(options =>
            {
                options.LoginPath = new PathString("/Account/SignIn");
                options.Cookie.Name = ".AspNet.SharedCookie";
            })

Моя страница входа в систему использует виджет Okta, поэтому нажатие кнопки входа отправляет пользователя в Okta, Okta делает свое дело, а затем отправляет пользователя обратно в приложение на каждый загадочный URL-адрес "код авторизации / обратного вызова" , Этот URL обрабатывается промежуточным ПО Okta.

Промежуточное программное обеспечение обрабатывает токены, отправляемые из Okta, вызывает конечную точку / userinfo для получения утверждений (при условии, что для этого свойства установлено значение true) и заполняет ClaimsPrincipal.

Вот часть, которую я пропустил Что он делает, так это устанавливает повара ie (s). Этот повар ie - это то, что, с этого момента, инфраструктура. net будет проверять, чтобы определить, кто является пользователем и аутентифицированы ли они. Я совершенно не понял этого. Я думал, что промежуточное программное обеспечение будет делать вызовы / авторизации или что-то в этом роде в фоновом режиме.

Итак, большой урок, который я усвоил здесь, заключается в следующем: только потому, что оба приложения используют тот же сервер OpenID не означает, что они могут легко обмениваться аутентификацией / сессиями. Для того, чтобы настоящий SSO работал без сбоев, они также должны разделить повара ie. И это подводит меня ко второму открытию: совместное использование файлов cookie для основных приложений ASP. NET. Короткая версия: вы должны:

a. Имя повара ie одинаково в обоих приложениях b. Используйте интерфейс IDataProtection для хранения ваших ключей cook ie там, где могут получить оба приложения (я выбрал Azure). c. Убедитесь, что домен cook ie одинаков для обоих приложений

Итак, в конце концов, это то, что мой код выглядел сквозным (при запуске каждого приложения). Я до сих пор имею дело с некоторыми странностями, специфичными для Nopcommerce c, но, надеюсь, они скоро уладятся.

            var oktaMvcOptions = new OktaMvcOptions()
            {
                OktaDomain = oktaDomain,
                ClientId = clientId,
                ClientSecret = clientSecret,
                Scope = new List<string> { "openid", "profile", "email", "address", "groups" },
                AuthorizationServerId = authServerId,
                GetClaimsFromUserInfoEndpoint = true
            };

            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference(storageContainerName);
            var blob = container.GetBlockBlobReference("somefilename.xml");

            services.AddDataProtection().SetApplicationName("somesharedappname").PersistKeysToAzureBlobStorage(blob);

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie(options =>
            {
                options.LoginPath = new PathString("/Account/SignIn");
                options.Cookie.Name = "somesharedcookiename";
            })
            .AddOktaMvc(oktaMvcOptions);

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

...