Вы когда-нибудь задумывались, как защитить свой API, чтобы только авторизованные пользователи могли получать данные? JWT — это как электронный пропуск, который выдается после логина и действует определенное время. В этой статье я покажу, как настроить JWT-аутентификацию в Yii2, используя простой и понятный подход. Вы научитесь создавать безопасный API, который будет удобен и для ваших клиентов, и для вас.
Ссылка на оригинальную статьюЧто такое JWT и зачем он нужен?
JWT (JSON Web Token) — это компактный и безопасный способ передачи данных между клиентом и сервером. Представьте, что вы приходите в спортзал и получаете браслет с QR-кодом. Пока браслет действует, вы проходите без предъявления паспорта. JWT работает аналогично: после логина сервер выдает токен, и клиент отправляет его с каждым запросом. Сервер проверяет токен и, если он валиден, выполняет запрос.
Почему именно JWT, а не сессии? Сессии хранятся на сервере и занимают память, а JWT — самодостаточен: он содержит всю информацию о пользователе и подпись. Это идеально для API, где клиенты могут быть мобильными приложениями, SPA или другими серверами.
Настройка проекта Yii2
Для начала нам понадобится установленный Yii2. Если у вас его нет, создайте проект с помощью Composer:
composer create-project --prefer-dist yiisoft/yii2-app-advanced api-demo
Перейдите в папку проекта и установите расширение для JWT. Рекомендую использовать firebase/php-jwt — оно легкое и популярное.
composer require firebase/php-jwt
Теперь создадим базу данных и таблицу пользователей. Для простоты используем стандартную схему Yii2 с таблицей user, но добавим поле api_token для хранения токена (необязательно, если вы будете проверять только подпись). В этом руководстве мы будем генерировать токен на основе ID пользователя и секретного ключа, поэтому дополнительное поле не требуется.
Убедитесь, что у вас настроено подключение к БД в common/config/main-local.php.
Установка JWT-компонента в Yii2
Теперь настроим компонент JWT в конфигурации приложения. Откройте common/config/main.php и добавьте следующий код в секцию components:
'components' => [
// ... другие компоненты
'jwt' => [
'class' => 'sizeg\jwt\Jwt',
'key' => 'your-secret-key-here', // замените на свой секретный ключ
'jwtValidationData' => [
'class' => 'sizeg\jwt\JwtValidationData',
'audience' => 'your-audience',
'subject' => 'your-subject',
],
],
],
Здесь мы используем пакет sizeg/yii2-jwt, который удобно интегрируется с Yii2. Установите его вместо firebase, если еще не сделали:
composer require sizeg/yii2-jwt
Этот компонент автоматически проверяет токен при каждом запросе, если вы укажете его в поведении контроллера. Мы это сделаем чуть позже.
Создание контроллера для логина и получения токена
Создадим контроллер AuthController, который будет обрабатывать POST-запрос на /auth/login. Клиент отправляет логин и пароль, а контроллер проверяет их и возвращает JWT-токен.
Создайте файл api/modules/v1/controllers/AuthController.php (или в любом другом месте, где у вас API).
namespace api\modules\v1\controllers;
use Yii;
use yii\rest\Controller;
use api\modules\v1\models\User;
use sizeg\jwt\Jwt;
use sizeg\jwt\JwtHttpBearerAuth;
class AuthController extends Controller
{
public $modelClass = 'api\modules\v1\models\User';
public function behaviors()
{
$behaviors = parent::behaviors();
// Отключаем аутентификацию для этого контроллера, кроме метода login
$behaviors['authenticator'] = [
'class' => JwtHttpBearerAuth::class,
'optional' => ['login'],
];
return $behaviors;
}
public function actionLogin()
{
$request = Yii::$app->request->post();
$user = User::findByUsername($request['username']);
if (!$user || !Yii::$app->security->validatePassword($request['password'], $user->password_hash)) {
throw new \yii\web\UnauthorizedHttpException('Invalid credentials');
}
$jwt = Yii::$app->jwt;
$token = $jwt->getBuilder()
->setIssuer('your-issuer') // кто выдал токен
->setAudience('your-audience') // для кого токен
->setId($user->id, true) // ID пользователя
->setIssuedAt(time()) // время выпуска
->setExpiration(time() + 3600) // срок действия 1 час
->sign($jwt->getSigner(), $jwt->getKey()) // подпись
->getToken();
return [
'token' => (string)$token,
];
}
}
Обратите внимание: метод findByUsername нужно реализовать в модели User. Если вы используете стандартную модель из Yii2, добавьте такой метод:
public static function findByUsername($username)
{
return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
}
Также не забудьте, что пароль должен быть захэширован с помощью Yii::$app->security->generatePasswordHash() при создании пользователя.
Защита API-контроллеров с помощью JWT
Теперь, когда у нас есть механизм выдачи токена, нужно защитить остальные контроллеры. Для этого в каждом контроллере, который требует аутентификации, добавьте поведение JwtHttpBearerAuth. Например, создадим контроллер ProfileController:
namespace api\modules\v1\controllers;
use yii\rest\ActiveController;
use sizeg\jwt\JwtHttpBearerAuth;
class ProfileController extends ActiveController
{
public $modelClass = 'api\modules\v1\models\User';
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => JwtHttpBearerAuth::class,
];
return $behaviors;
}
// Действие для получения профиля текущего пользователя
public function actionIndex()
{
$user = Yii::$app->user->identity;
return $user;
}
}
Теперь при обращении к /profile без токена вы получите ошибку 401. А если отправите токен в заголовке Authorization: Bearer <token>, то получите данные пользователя.
Настройка маршрутов и CORS
Для работы API нужно настроить правила маршрутизации в config/main.php модуля api. Добавьте в urlManager следующие правила:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'v1/auth',
'extraPatterns' => [
'POST login' => 'login',
],
],
[
'class' => 'yii\rest\UrlRule',
'controller' => 'v1/profile',
],
],
]
Не забудьте настроить CORS (Cross-Origin Resource Sharing), если ваш API будут использовать фронтенд-приложения с другого домена. Для этого можно использовать поведение yii\filters\Cors. Добавьте его в контроллер:
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['corsFilter'] = [
'class' => \yii\filters\Cors::class,
'cors' => [
'Origin' => ['*'],
'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'DELETE'],
'Access-Control-Allow-Headers' => ['Content-Type', 'Authorization'],
],
];
return $behaviors;
}
Обратите внимание, что CORS должен быть настроен до аутентификации, иначе предварительные OPTIONS-запросы будут отклонены.
Проверка работы API с помощью Postman или cURL
Давайте протестируем. Сначала получим токен:
curl -X POST http://api-demo.local/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"demo","password":"demo123"}'
В ответ вы получите JSON с токеном. Скопируйте его и используйте для запроса профиля:
curl http://api-demo.local/v1/profile \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
Если все настроено правильно, вы увидите данные пользователя. Если нет — проверьте логи и убедитесь, что секретный ключ в конфигурации совпадает с тем, что используется при подписи.
Практические советы и лайфхаки
params-local.php, который не попадает в репозиторий.
Вот несколько рекомендаций, которые помогут избежать типичных ошибок:
- Устанавливайте короткий срок действия токена (например, 15-30 минут) и обновляйте его с помощью refresh-токена.
- Используйте HTTPS в продакшене, чтобы токен не перехватили.
- Для больших проектов рассмотрите использование OAuth2, но для большинства задач JWT достаточно.
- Проверяйте не только подпись, но и срок действия токена. В компоненте
sizeg/yii2-jwtэто делается автоматически. - Логируйте ошибки аутентификации, чтобы быстро находить проблемы.
Сравнение JWT и обычных сессий
| Критерий | JWT | Сессии |
|---|---|---|
| Хранение на сервере | Не требуется, токен самодостаточен | Требуется, данные хранятся в памяти или БД |
| Масштабируемость | Отличная, подходит для распределенных систем | Проблемы при горизонтальном масштабировании |
| Мобильные приложения | Удобно, не нужны куки | Сложнее, нужна поддержка кук |
Заключение
Мы создали API с JWT-аутентификацией на Yii2. Теперь вы знаете, как выдавать токены и защищать эндпоинты. Это основа для многих современных приложений. В итоге вы получили работающий механизм, который можно расширять: добавлять роли, права, refresh-токены. Главное — не забывайте о безопасности и всегда проверяйте входящие данные.
Если вы хотите сэкономить время и заказать разработку API под ключ, обратитесь в Digital-студию WNDER — мы поможем с любыми задачами.


