Обработка событий сессии и сценарии авторизации
Обзор возможностей
Статья описывает, как приложение реагирует на события сессии и какие сценарии авторизации нужно обработать при интеграции с OpenID Connect Session Management.
Настройка модуля описана здесь.
Как приложение узнаёт об изменениях сессии
RP iframe проверяет полученный при авторизации session_state и на основании этого отправляет события в ваше приложение через postMessage.
Приложение должно слушать эти события и реагировать.
window.addEventListener('message', (event) => {
// Проверяем, что сообщение пришло с доверенного origin
if (event.origin !== 'https://your-project.softline.ru') {
return;
}
if (event.data.type === 'oidc_session_changed') {
console.log('Сессия изменилась');
window.location.href = '/login?prompt=none';
}
});Что здесь происходит:
- Слушаем все postMessage.
- Отбрасываем сообщения с чужих origin — это защита от подделки.
- Если пришло событие oidc_session_changed — перенаправляем пользователя на повторную авторизацию.
Событие oidc_session_changed отправляется, если пользователь:- вышел из системы;
- вошёл под другим аккаунтом;
- переавторизовался;
- изменил состояние сессии у провайдера.
Что делать при изменении сессии (рекомендуемый алгоритм):
- Выполнить повторную авторизацию.
- Получить новый session_state.
- Перезапустить RP iframe.
Сценарии использования
Первый вход пользователя
При первом входе session_state отсутствует.
Последовательность действий для получения:
- Перенаправьте пользователя на авторизацию (на OAuth2 Provider) либо на тихую проверку:
return redirect()->away( 'https://login.softline.ru/oauth2/authorize?' . http_build_query([ 'client_id' => 'abc123xyz', 'redirect_uri' => 'https://your-project.softline.ru/oauth2/callback', 'response_type' => 'code', 'scope' => 'auth.data.personal.get', 'state' => 'sdfwgdgd6SF', 'prompt' => 'none' ]) ); - Провайдер возвращает пользователя на адрес редиректа (redirect_uri), ответ в том числе содержит актуальный session_state.
В случае, если в ответ получена ошибка, см. описание кейса далее. - Приложение проверяет подлинность ответа (state из ответа совпадает с state из запроса), и в случае корректности сохраняет session_state.
- Приложение создаёт RP iframe.
- Начинается мониторинг сессии.
Важно! Параметр session_state нужно сохранять при любом ответе провайдера, даже если это ошибка (access_denied). Провайдер всегда передает самую актуальную версию session_state.
Повторный вход пользователя
Если session_state уже сохранён:
- повторная авторизация не нужна;
- RP iframe запускается сразу;
- мониторинг начинается автоматически.
Успешная авторизация
- Провайдер перенаправляет пользователя на redirect_uri и передает в ответе параметры, в том числе session_state.
/callback?code=def50200b07...&state=s761MQGea2Yt...&session_state=7fd534dab... - Обмен кода на токен:
Ответ:
curl -X POST "https://login.softline.ru/oauth2/token" \ -d "grant_type=authorization_code" \ -d "code=def50200b07..." \ -d "redirect_uri=https://your-project.softline.ru/oauth2/callback" \ -d "client_id=abc123xyz" \ -d "client_secret=your_client_secret"{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0N", "token_type": "Bearer", "expires_in": 7200, "refresh_token": "tGzv3my0kx0BYrHjWmF2nkdZv9", "scope": "auth.data.personal.get" } - Получение данных пользователя:
curl -X GET "https://login.softline.ru/api/v1/auth/user" \ -H "Authorization: Bearer ACCESS_TOKEN" - Дальнейшие действия:
- Создайте или обновите пользователя.
- Авторизуйте его в приложении.
- Создайте RP iframe.
Сценарий: access_denied
session_state может прийти не только при успешной авторизации, но и при ошибке access_denied. Это нормальное поведение провайдера.
Пример ответа:
/callback?
state=Eqk5886Ch...
&session_state=8d0717a9...
&error=access_denied
&error_description=The+resource+owner+or+authorization+server+denied+the+request.
&hint=Unauthenticated&message=The+resource+owner+or+authorization+server+denied+the+request
В контексте управления сессией access_denied обычно означает, что пользователь больше не авторизован у провайдера.
Например:
- нажал Выйти;
- сессия истекла;
- был разлогинен на стороне провайдера.
При получении error = access_denied необходимо:
- Разлогинить пользователя в вашем приложении.
- Очистить локальную сессию.
- Показать страницу логина.
session_state нужно сохранить даже при access_denied — он понадобится для дальнейшей работы RP iframe.