Итак, здесь есть несколько возможных решений:
- Вызовите конечную точку OIDC UserInfo, чтобы получать обновленные утверждения пользователей по каждому запросу.
- Уменьшите время жизни файлов cookie, чтобы чаще автоматически обновлять информацию о пользователе.
- Реализуйте пользовательскую конечную точку на IdentityServer, чтобы она могла публиковать информацию об изменении профиля в списке подписанных клиентов (например, в вашем веб-приложении).
- Заставить IdentityServer принудительно выполнять единый выход при изменении данных профиля пользователя.
С точки зрения сложности реализации, уменьшение времени жизни файлов cookie является самым простым (просто измените срок действия файлов cookie), но это не гарантирует актуальных требований и видно пользователю (частые перенаправления на IdentityServer, хотя вход в систему невозможен). требуется, если срок действия маркера доступа все еще действителен)
Вызов веб-приложением конечной точки UserInfo при каждом запросе является следующим простым (см. пример ниже), но имеет худшие последствия для производительности. Каждый запрос будет производить круговое путешествие к IdentityServer.
Модель конечной точки/подписчика будет иметь наименьшую нагрузку на производительность. Запросы UserInfo к IdentityServer будут происходить ТОЛЬКО тогда, когда информация о профиле пользователя действительно изменилась. Это было бы немного сложнее реализовать:
- В вашем проекте IdentityServer вам нужно будет изменить изменения в данных профиля и опубликовать http-сообщение в своем веб-приложении. Сообщение может просто содержать идентификатор измененного пользователя. Это сообщение должно быть каким-то образом аутентифицировано, чтобы злоумышленники не могли аннулировать законные пользовательские сеансы. Для этого вы можете включить токен носителя ClientCredentials.
- Ваше веб-приложение должно будет получить и аутентифицировать сообщение. Необходимо будет сохранить измененный идентификатор пользователя где-нибудь, доступном для делегата OnValidatePrincipal (скорее всего, через службу в контейнере DI)
- Затем делегат Cookie OnValidatePrincipal внедрит эту локальную службу, чтобы проверить, изменилась ли информация о пользователе перед проверкой принципала.
Примеры кода
Получайте обновленную информацию о пользователе с конечной точки при каждом вызове
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "NameOfYourCookieAuthSchemeHere",
Events = new CookieAuthenticationEvents()
{
OnValidatePrincipal = async context =>
{
// Get updated UserInfo from IdentityServer
var accessToken = context.Principal.Claims.FirstOrDefault(c => c.Type == "access_token").Value;
var userInfoClient = new UserInfoClient("https://{IdentityServerUrlGoesHere}");
var userInfoResponse = await userInfoClient.GetAsync(accessToken);
// Invalidate Principal if Error Response
if (userInfoResponse.IsError)
{
context.RejectPrincipal();
await context.HttpContext.Authentication.SignOutAsync("NameOfYourCookieAuthSchemeHere");
}
else
{
// Check if claims changed
var claimsChanged = userInfoResponse.Claims.Except(context.Principal.Claims).Any();
if (claimsChanged)
{
// Update claims and replace principal
var newIdentity = context.Principal.Identity as ClaimsIdentity;
newIdentity.AddClaims(userInfoResponse.Claims);
var updatedPrincipal = new ClaimsPrincipal();
context.ReplacePrincipal(updatedPrincipal);
context.ShouldRenew = true;
}
}
}
}
});
Обновление при подписанном сообщении об изменении от IdentityServer. В этом примере предполагается, что вы создали службу (например, IUserChangedService), в которой хранятся идентификаторы пользователей, полученные в конечной точке от IdentityServer. У меня нет образцов принимающей конечной точки веб-приложения или службы.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "NameOfYourCookieAuthSchemeHere",
Events = new CookieAuthenticationEvents()
{
OnValidatePrincipal = async context =>
{
// Get User ID
var userId = context.Principal.Claims.FirstOrDefault(c => c.Type == "UserIdClaimTypeHere");
var userChangedService = context.HttpContext.RequestServices.GetRequiredService<IUserChangedService>();
var userChanged = await userChangedService.HasUserChanged(userId);
if (userChanged)
{
// Make call to UserInfoEndpoint and update ClaimsPrincipal here. See example above for details
}
}
}
});
В основных документах asp.net также есть пример этого, за исключением работы с локальной базой данных. Подход к методу OnValidatePrincipal такой же: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie#reacting-to-back-end-changes
Надеюсь это поможет!
person
kg743
schedule
12.05.2017