— Галиев Б.А 2020/07/27 10:06
Система «ЕСИ» реализует метод backchannel-logout для уведомления доверенных систем (Relying Parties) о выходе пользователя из учетной записи.
Уведомление происходит путем HTTP запроса на адрес backchannel_logout_uri, который заполняется при регистрации доверенной системы в ЕСИ.
При выходе пользователя формируется JWT токен, который содержит набор объектов Claim пользователя.
Пример полезной нагрузки JWT токена
{ "nbf": 1595844077, "exp": 1595844377, "iss": "https://localhost:7001", "sub": "1000000", "aud": "mvc-client", "iat": 1595844077, "jti": "D5D482E197A188EC89B640DDA0AB0961", "sid": "6BC6B6F445B4CE79AAAC84F7461A0036", "events": { "http://schemas.openid.net/event/backchannel-logout": {} } }
Обработка события выхода Backchannel logout на стороне доверенной системы (Relying party) состоит из следующих этапов:
При инвалидации сессионной cookie используются два значения из JWT токена:
Пример:
[HttpPost] [AllowAnonymous] public async Task<IActionResult> Index(string logout_token) { //Добавьте обработчики исключений //Валидация токена var user = await ValidateLogoutToken(logout_token); var sub = user.FindFirst("sub")?.Value; var sid = user.FindFirst("sid")?.Value; //Добавление sub sid для инвалидации сессии пользователя в Relying Party LogoutSessions.Add(sub, sid); return Ok(); }
LogoutSessions это тестовый класс который содержит пару sub, sid в памяти.
Если пользователь через браузер осуществит вызов в Relying party, система должна проверить на наличие идентификатора и сессии пользователя в этой коллекции.
Если sub и sid пользователя есть в этой колекции то система должна уничтожить cookie тем самым совершив logout на стороне Relying party
Пример инвалидации сессионной cookie на Asp.Net Core 3
public class CookieEventHandler : CookieAuthenticationEvents { public CookieEventHandler(LogoutSessionManager logoutSessions) { LogoutSessions = logoutSessions; } public LogoutSessionManager LogoutSessions { get; } public override async Task ValidatePrincipal(CookieValidatePrincipalContext context) { if (context.Principal.Identity.IsAuthenticated) { var sub = context.Principal.FindFirst("sub")?.Value; var sid = context.Principal.FindFirst("sid")?.Value; if (LogoutSessions.IsLoggedOut(sub, sid)) { context.RejectPrincipal(); await context.HttpContext.SignOutAsync(); // todo: if we have a refresh token, it should be revoked here. } } } }