Кроссдоменная SSO — IO7 Framework
Внимание
Данная статья документации написана нейросетью. Возможны некоторые расхождения и неточность информации!
Обзор
IO\Auth\CrossDomainSSO — класс для кроссдоменной авторизации. Позволяет пользователям, авторизованным на одном домене, получать доступ к другим доменам без повторного входа. Использует механизм обмена токенами вместо сторонних cookies.
Формат токена: base64url(header).base64url(payload).base64url(hmac) — не JWT.
Инициализация
$sso = \IO\Auth\CrossDomainSSO::init([
'sso_base_url' => 'https://sso.example.com',
'sso_secret' => 'your-secret-key',
]);
Конфигурация
| Параметр | Тип | Значение по умолчанию | Обязателен | Описание |
|---|---|---|---|---|
sso_base_url | string | — | Да | Базовый URL SSO-сервера (обязательный) |
sso_secret | string | — | Да | Общий секрет для HMAC-подписи (обязательный) |
Методы
init(array $config): self
Инициализация SSO-клиента.
| Параметр | Тип | Значение по умолчанию | Обязателен | Описание |
|---|---|---|---|---|
$config | array{sso_base_url: string, sso_secret: string} | — | Да | Конфигурация |
| Возврат | self | Экземпляр CrossDomainSSO | ||
| Исключение | \InvalidArgumentException | Если sso_base_url или sso_secret пустые |
CrossDomainSSO::init([
'sso_base_url' => 'https://sso.example.com',
'sso_secret' => 'my-secret-key',
]);
getInstance(): self
Получить единственный экземпляр класса. Должен вызываться после init().
| Параметр | Тип | Значение по умолчанию | Обязателен | Описание |
|---|---|---|---|---|
| Возврат | self | Экземпляр CrossDomainSSO | ||
| Исключение | \RuntimeException | Если init() не был вызван |
$sso = CrossDomainSSO::getInstance();
getCrossDomainToken(string $userId, array $data = []): string
Создать токен для кроссдоменной авторизации.
| Параметр | Тип | Значение по умолчанию | Обязателен | Описание |
|---|---|---|---|---|
$userId | string | — | Да | Идентификатор пользователя |
$data | array | [] | Нет | Дополнительные данные (например, ['role' => 'admin']) |
| Возврат | string | Подписанный токен |
$token = $sso->getCrossDomainToken('user-123', [
'role' => 'admin',
'email' => 'user@example.com',
]);
validateCrossDomainToken(string $token, string $domain): ?array
Валидация токена с другого домена.
| Параметр | Тип | Значение по умолчанию | Обязателен | Описание |
|---|---|---|---|---|
$token | string | — | Да | Токен для проверки |
$domain | string | — | Да | Домен, для которого был выдан токен |
| Возврат | array|null | Данные токена или null если невалиден |
$data = $sso->validateCrossDomainToken($token, 'example.com');
if ($data !== null) {
echo 'User: ' . $data['user_id'];
}
exchangeToken(string $token, string $fromDomain, string $toDomain): ?string
Обмен токеном между доменами.
| Параметр | Тип | Значение по умолчанию | Обязателен | Описание |
|---|---|---|---|---|
$token | string | — | Да | Исходный токен |
$fromDomain | string | — | Да | Домен-источник |
$toDomain | string | — | Да | Домен-получатель |
| Возврат | string|null | Новый токен или null при ошибке |
$newToken = $sso->exchangeToken(
$token,
'app1.example.com',
'app2.example.com'
);
createSessionCookie(string $userId): string
Создать cookie для сессии.
| Параметр | Тип | Значение по умолчанию | Обязателен | Описание |
|---|---|---|---|---|
$userId | string | — | Да | Идентификатор пользователя |
| Возврат | string | Значение cookie |
$cookie = $sso->createSessionCookie('user-123');
setcookie('sso_session', $cookie, [
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
validateSessionCookie(string $cookie): ?array
Валидация cookie сессии.
| Параметр | Тип | Значение по умолчанию | Обязателен | Описание |
|---|---|---|---|---|
$cookie | string | — | Да | Значение cookie |
| Возврат | array|null | Данные сессии или null |
$session = $sso->validateSessionCookie($_COOKIE['sso_session'] ?? '');
if ($session !== null) {
$userId = $session['user_id'];
}
Пример: Кроссдоменная SSO (VKPlay-style)
1. SSO сервер (sso.example.com)
$sso = \IO\Auth\CrossDomainSSO::init([
'sso_base_url' => 'https://sso.example.com',
'sso_secret' => getenv('SSO_SECRET'),
]);
// POST /api/sso/exchange
class SsoExchangeApi extends \IO\Api\CrudApi
{
public function doPostData(ApiResult $result, array $params): ApiResult
{
$sso = CrossDomainSSO::getInstance();
$token = $params['token'] ?? '';
$fromDomain = $params['from_domain'] ?? '';
$toDomain = $params['to_domain'] ?? '';
$newToken = $sso->exchangeToken($token, $fromDomain, $toDomain);
return $result->showSuccess([
'token' => $newToken,
]);
}
}
2. Клиентский домен (app1.example.com)
// Проверка сессии через AJAX
class CheckSessionApi extends \IO\Api\CrudApi
{
public function doGetData(ApiResult $result, array $params): ApiResult
{
$sso = CrossDomainSSO::getInstance();
$cookie = $_COOKIE['sso_session'] ?? '';
$session = $sso->validateSessionCookie($cookie);
if ($session !== null) {
return $result->showSuccess([
'user' => ['id' => $session['user_id']],
]);
}
return $result->showSuccess([
'auth_required' => true,
]);
}
}
3. JavaScript на клиенте
async function checkSession() {
const response = await fetch('https://app1.example.com/api/auth/check', {
credentials: 'include'
});
const data = await response.json();
if (data.auth_required) {
// Редирект на SSO
window.location.href = 'https://sso.example.com/login?redirect=app1.example.com';
} else {
console.log('Пользователь:', data.user);
}
}