Міграція застарілого додатка на Laravel по одному маршруту залишає вас із двома додатками та одним користувачем, який залогінений лише в одному з них. Користувач входить у старій частині на CodeIgniter чи кастомному PHP, переходить на маршрут, оброблений Laravel, і Laravel, не знаючи нічого про цю сесію, надсилає його до форми входу. Пакет Laravel Legacy Bridge від Кріса Келлера зчитує cookie застарілої сесії на неавтентифікованих запитах, декодує payload сесії з legacy-бази даних і автентифікує відповідного користувача в Laravel.
Основні можливості пакета
Пакет охоплює наступний функціонал:
- Middleware-міст, який спрацьовує лише на неавтентифікованих запитах і припиняє звертатися до legacy-сховища після того, як Laravel створює власну сесію
- Декодування payload для нативного PHP session encoding, JSON, Laravel-формату
base64(serialize()) та зашифрованих payload
- Resolver-драйвери для визначення ID користувача в payload: авто-визначення, явний ключ у dot-нотації або власний клас
- Типізовані події для успішних переходів, відомих помилок та неочікуваних винятків, без власного логування
- Інвалідація legacy-сесій, щоб конкретна застаріла сесія могла бути використана лише один раз
- Інтерактивна команда встановлення з пресетами для фреймворків, плюс команда
verify для тестування налаштувань перед реальним трафіком
- Опціональне перенесення контексту для значень на кшталт locale або ID кошика, що зберігаються в legacy-payload
Як працює міст
Реєстрація одного middleware додає міст у шлях запиту:
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\Chr15k\LegacyBridge\Http\Middleware\LegacySessionBridge::class,
]);
})
На неавтентифікованому запиті він зчитує legacy-cookie (за замовчуванням PHPSESSID), знаходить рядок у таблиці legacy-сесій, декодує payload, визначає ID користувача та викликає loginUsingId(). Потім Laravel записує власну сесію, і подальші запити вже не звертаються до legacy-сховища. Service provider також виключає legacy-cookie з middleware EncryptCookies, тому не потрібно підтримувати список encryptCookies().
Резолвери та формати payload
Кожен застарілий додаток зберігає ID користувача під різним ключем, тому пошук є конфігурованим. Виберіть resolver-драйвер у config/legacy-bridge.php:
// Auto: пробує відомі шаблони (за замовчуванням)
'resolver' => ['driver' => 'auto'],
// Key: явний шлях у dot-нотації
'resolver' => ['driver' => 'key', 'key' => 'user_id'],
// Custom: власна реалізація
'resolver' => ['driver' => 'custom', 'class' => \App\Bridge\LegacyUserResolver::class],
README рекомендує починати з auto і переходити на key або custom перед продакшеном. Кастомний resolver також є місцем, де можна змапити старі ID користувачів на нові, якщо під час міграції таблиця users була пересіяна. Формат payload - це окреме налаштування (auto, php_session, json, laravel або encrypted), а зашифрований формат зчитує ключ застарілого додатка з LEGACY_BRIDGE_APP_KEY.
Події
Міст нічого не записує у ваші лог-файли. Він диспатчить LegacySessionBridged при успіху, LegacySessionBridgeFailed для відомих помилок і LegacySessionBridgeError для неочікуваних винятків, залишаючи звітування вашим слухачам.
Помилки містять enum BridgeFailureReason з вісьмома варіантами, серед яких MissingCookie, AmbiguousCookie, SessionExpired, PayloadDecodeFailed та UserNotResolved. Деякі вказують на неправильну конфігурацію, інші є звичайними, як-от сесія з вичерпаним часом. Подія помилки також несе DTO BridgeContext, що містить все, що міст визначив до зупинки:
$event->context->cookieName
$event->context->sessionId // визначений ID сесії (якщо досягнуто)
$event->context->payload // декодований payload (якщо досягнуто)
$event->context->userId // визначений ID користувача (якщо досягнуто)
$event->context->requestContext // ['ip', 'path', 'method', 'user_agent']
Встановлення
composer require chr15k/laravel-legacy-bridge
php artisan legacy-bridge:install
Команда встановлення є інтерактивною. Вона включає пресети для популярних legacy-фреймворків, збирає облікові дані бази даних і записує записи .env за вас.
Команда verify
Неправильно налаштований міст падає на реальних cookies проти реальної legacy-бази даних, що не є тим, що тестує ваш тестовий набір. Пакет постачається з командою, яка перевіряє конфігурацію проти цієї бази даних:
php artisan legacy-bridge:verify
php artisan legacy-bridge:verify --session-id=a_real_session_id
Запустіть її без параметрів, і вона перевірить, що конфіг читається, legacy-база даних доступна, таблиця сесій існує та має рядки, resolver налаштований, і немає конфліктів імен cookies. Передайте реальний ID сесії, і вона повідомить, що міст зробив би з цією сесією: виявлений формат, знайдені ключі payload, визначений ID користувача, підтверджено існування користувача. Вона нікого не автентифікує і нічого не модифікує.
Обмеження та безпека
Перший реліз підтримує лише database-сесії, не file, Redis чи Memcached драйвери. Він працює з веб-запитами, не зі stateless API-запитами, і лише з дефолтним auth guard. Потребує Laravel 13 та PHP 8.3 або новіше.
Прочитайте розділ безпеки README перед деплоєм. Міст десеріалізує payload, зчитані безпосередньо з таблиці legacy-сесій, що робить цю базу даних межею довіри; автор рекомендує використовувати облікові дані лише для читання, де це можливо. Legacy-cookie передається незашифрованим за дизайном, так само, як це було в старому додатку, тому обидва додатки потребують HTTPS. Дефолтна стратегія інвалідації after_write видаляє legacy-сесію після того, як Laravel записує власну, і документація радить не встановлювати її на never у продакшені.
Вихідний код та повний посібник користувача, що охоплює пресети фреймворків, стратегії інвалідації та усунення несправностей, доступні на GitHub.