Я думал, что поделюсь результатами своих тестов, поскольку они обнаружили некоторые вещи, которые я действительно не ожидал. Возможно, эти вещи очевидны / известны большинству из вас, но для меня они определенно оказались хитрыми.
Первое, что я узнал, это то, что вы должны указать 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 Базовом приложении и вы самостоятельно размещаете страницу входа, поток выглядит примерно так:
- Пользователь пытается получить доступ к защищенному ресурсу
- Маркер [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);
Надеюсь, это поможет кому-то, кто в итоге столкнется с такими же проблемами. Если кто-то может предложить лучший механизм для реализации этого, я хотел бы услышать ваши идеи и предложения.