Миграция с JWT на видеобезопасность: От токенов к сессиям с Passport и Sanctum

Пошаговое руководство по миграции системы аутентификации с JSON Web Tokens (JWT) на решения Laravel Sanctum и Passport. Статья охватывает причины миграции, установку, настройку, адаптацию контроллеров и фронтенда, а также особенности защиты видеоконтента с помощью подписанных URL и управления токенами.
JSON Web Tokens (JWT) долгое время были золотым стандартом для аутентификации в SPA и мобильных приложениях из-за своей статичности и отсутствия состояния. Однако с ростом сложности приложений и ужесточением требований безопасности их недостатки — неотзывчивость, сложность с инвалидацией и хранение на клиенте — стали более явными. В этой статье мы рассмотрим пошаговый процесс миграции системы аутентификации с JWT на более безопасные и управляемые подходы, предлагаемые Laravel: Passport для OAuth2 и Sanctum для простой аутентификации на основе сессий/токенов, с особым вниманием к работе с видеоконтентом.

Первый шаг — оценка текущей реализации. Предположим, у вас есть Laravel-бэкенд, который выдает JWT через кастомный guard или пакет вроде `tymon/jwt-auth`. Фронтенд (Vue.js/React) хранит токен в localStorage и отправляет его в заголовке `Authorization: Bearer `. Проблемы: чтобы разлогинить пользователя, нужно ждать истечения срока жизни токена (TTL); компрометация токена дает доступ до его экспирации; сложная логика обновления refresh-токенов.

Шаг 2: Выбор целевого решения. Laravel предлагает два основных инструмента:
  • **Sanctum**: Идеально для SPA, работающих на том же домене (или с правильно настроенным CORS), и для мобильных приложений. Он предоставляет легковесную аутентификацию на основе сессий для браузерных SPA и токенов API для мобильных клиентов. Токены Sanctum можно легко отозвать.
  • **Passport**: Полноценная реализация OAuth2 сервера. Подходит, если у вас есть несколько клиентов (веб, мобильное, сторонние приложения), требующих стандартизированный протокол. Более тяжеловесный, но и более функциональный.
Для большинства случаев миграции с простого JWT, где есть один фронтенд, **Sanctum будет предпочтительным и более простым путем**. Мы рассмотрим его.

Шаг 3: Установка и настройка Sanctum. Установите пакет через Composer.

composer require laravel/sanctum

Опубликуйте конфигурации и миграции.

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

Выполните миграцию для создания таблицы `personal_access_tokens`.

php artisan migrate

Добавьте middleware `\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class` в группу `api` в `app/Http/Kernel.php`. Это ключевой момент: для запросов из SPA Sanctum будет использовать сессии (куки), а для мобильных — токены.

Шаг 4: Адаптация модели User. Убедитесь, что ваша модель `User` использует трейт `Laravel\Sanctum\HasApiTokens`.

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
 use HasApiTokens, HasFactory, Notifiable;
}

Шаг 5: Модификация контроллеров аутентификации. Перепишите ваш `AuthController`. Эндпоинт входа вместо генерации JWT будет выполнять стандартную попытку входа через `Auth::attempt` и создавать сессию (для SPA) или токен (для мобильных).

public function login(Request $request)
{
 $credentials = $request->only('email', 'password');

 if (Auth::attempt($credentials)) {
 $user = Auth::user();
 // Для мобильного клиента или стороннего API создаем токен
 if ($request->wantsJson() || $request->is('api/*')) {
 $token = $user->createToken('auth_token')->plainTextToken;
 return response()->json([
 'user' => $user,
 'access_token' => $token,
 'token_type' => 'Bearer',
 ]);
 }
 // Для SPA на том же домене аутентификация через сессию произойдет автоматически
 return response()->json(['user' => $user]);
 }

 return response()->json(['error' => 'Unauthorized'], 401);
}

Шаг 6: Защита маршрутов API. Вместо кастомного JWT middleware теперь используйте встроенный `auth:sanctum`. Он будет проверять либо аутентифицированную сессию (для SPA), либо валидный токен из заголовка `Authorization: Bearer ...`.

Route::middleware('auth:sanctum')->group(function () {
 Route::get('/user', function (Request $request) {
 return $request->user();
 });
 // Ваши защищенные маршруты, например, для видео
 Route::post('/video/upload', [VideoController::class, 'upload']);
});

Шаг 7: Адаптация фронтенда (SPA на том же домене). Это самый простой сценарий. Убедитесь, что ваш фронтенд отправляет запросы с `credentials: 'include'` (в axios: `axios.defaults.withCredentials = true;`). Удалите всю логику ручного добавления JWT в заголовки. Sanctum автоматически будет использовать куки сессии Laravel. Запросы к API будут считаться аутентифицированными, если пользователь вошел в систему.

Шаг 8: Адаптация мобильного приложения или отдельного фронтенда. Для нативных приложений или SPA на другом домене используйте токен, полученный при логине. Сохраните `access_token` и отправляйте его в заголовке, как и раньше. Но теперь токен можно отозвать! Эндпоинт выхода должен удалять токен.

public function logout(Request $request)
{
 // Отзыв текущего токена (для мобильных/токенов)
 $request->user()->currentAccessToken()->delete();
 // Или отзыв всех токенов: $request->user()->tokens()->delete();

 // Для SPA также можно вызвать Auth::logout() для очистки сессии
 Auth::guard('web')->logout();

 return response()->json(['message' => 'Logged out']);
}

Шаг 9: Особенности работы с видеоконтентом. Если ваше приложение загружает или стримит видео, важно обеспечить защиту этих ресурсов. С JWT вы, возможно, передавали токен в параметре запроса или заголовке для доступа к видеофайлу. С Sanctum подход может быть аналогичным для токенов. Однако для SPA, обслуживающих видео через теги ``, браузер не отправляет куки сессии по умолчанию при cross-origin запросах. Решение: настроить CORS правильно (указав `credentials: true` на сервере) или использовать подписанные временные URL. Laravel может генерировать подписанные ссылки на защищенные видеофайлы, хранящиеся в S3 или локально, с ограниченным временем жизни.

use Illuminate\Support\Facades\Storage;

Route::middleware('auth:sanctum')->get('/video/{video}', function (Video $video) {
 // Генерация подписанного URL на 10 минут для S3
 $url = Storage::disk('s3')->temporaryUrl(
 $video->path, now()->addMinutes(10)
 );
 return redirect($url);
});

Шаг 10: Инвалидация и управление токенами. Одно из главных преимуществ — панель управления токенами. Вы можете создать простой интерфейс, где пользователь видит список своих активных токенов (устройств) и может их отозвать. Данные хранятся в таблице `personal_access_tokens`.

В заключение, миграция с JWT на Sanctum делает ваше приложение более безопасным и управляемым. Вы получаете возможность мгновенного отзыва доступа, более простую интеграцию с SPA на одном домене и надежную основу для роста. Процесс требует изменений на бэкенде и адаптации фронтенда, но результат — профессиональная система аутентификации, соответствующая современным стандартам Laravel.
443 4

Комментарии (10)

avatar
thc2t0jx3ntr 01.04.2026
Passport — это избыточно для большинства проектов. Sanctum идеально подошел для нашего SPA, переход был почти безболезненным.
avatar
t2jmf27y25o 02.04.2026
Наконец-то кто-то поднял тему отзывов токенов! Это была наша главная головная боль при использовании JWT в банковском модуле.
avatar
55unbl9n0128 02.04.2026
Интересный подход, но для нашего высоконагруженного API JWT пока выигрывает по производительности. Буду наблюдать за трендами.
avatar
j93jgnv 03.04.2026
Как junior dev, благодарен за четкое объяснение. Теперь понимаю, почему в новом проекте сразу стартовали с сессий.
avatar
ykxdndzarjl 03.04.2026
После утечки данных мы были вынуждены перейти. Sanctum + редис для хранения сессий — сейчас наш стандарт безопасности.
avatar
8wzhu8b7w 03.04.2026
Автор прав, но переход требует тщательного планирования. Рекомендую сначала протестировать на staging-окружении.
avatar
jqpywx3 04.04.2026
Миграция заняла у команды две недели, но безопасность сессий через Sanctum того однозначно стоила. Рекомендую.
avatar
33kik6 04.04.2026
Упомянутые проблемы решаются blacklist'ами для JWT, но да, их поддержка создает дополнительную сложность. Паритет.
avatar
h6si9uyjfofh 04.04.2026
Статья полезная, но не хватает сравнения нагрузки на базу данных между stateless JWT и stateful сессиями Sanctum.
avatar
843o4r6q5g1p 04.04.2026
Жаль, что не затронули тему микросервисов. В распределенных системах JWT все еще кажется более удобным решением.
Вы просмотрели все комментарии