Аутентификация в Yii2: частые ошибки новичков
Разбираем, где новички спотыкаются при настройке входа в Yii2: пустой findIdentityByAccessToken, забытый validateAuthKey, неверный класс identityClass и сессии, которые слетают после логина.

Вы поднимаете форму входа в Yii2, вводите логин и пароль, приложение молча возвращает вас на ту же страницу — без ошибки, без входа. Или наоборот: логин проходит, но на любой защищённой странице снова редирект на /site/login. Это не баг фреймворка, а незакрытые контракты интерфейса IdentityInterface и путаница между двумя способами хранения пароля. Ниже — конкретные места, где ломается аутентификация, и что именно в них исправить. Материал для Yii 2.0.x с шаблоном basic.
Что понадобится до начала
Речь про стандартный механизм на компоненте user и классе, реализующем IdentityInterface. Проверьте, что у вас есть:
- Yii 2.0.40 или новее (в старых сборках отличается поведение
ValidationAsset, но на логику входа это не влияет); - таблица пользователей с полями
password_hashиauth_key— неpasswordв открытом виде; - настроенный компонент
userвconfig/web.phpс указаннымidentityClass; - PHP 7.4+ с расширением, поддерживающим
password_hash()(по умолчанию есть).
Ошибка 1. identityClass указывает не на тот класс
Компонент user знает, кого грузить из сессии, только по значению identityClass. В шаблоне basic по умолчанию стоит демо-класс app\models\User с массивом пользователей прямо в коде. Как только вы завели таблицу и свою модель, но забыли поправить конфиг, вход идёт через демо-класс, а ваши записи из базы игнорируются.
// config/web.php
'components' => [
'user' => [
// должно указывать на вашу модель, а не на демо-класс
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
],
Проверка: временно вставьте в модель findByUsername() вызов var_dump(static::class) при отладке — вы должны увидеть имя своей модели, а не демо-класса из vendor.
Ошибка 2. Пустые методы IdentityInterface
Чтобы модель работала как identity, она реализует шесть методов. Новички генерируют заглушки Gii и оставляют их пустыми — код запускается, но логин молчит. Разберём три метода, которые ломают вход чаще всего.
findIdentity и findIdentityByAccessToken
findIdentity($id) вызывается при каждом запросе, чтобы восстановить пользователя из сессии по его id. Если метод возвращает null или ищет не по тому полю, вы залогинитесь, а на следующей странице вас выкинет.
public static function findIdentity($id)
{
// ищем по первичному ключу, а не по username
return static::findOne(['id' => $id]);
}
public static function findIdentityByAccessToken($token, $type = null)
{
// нужен только для REST/токенов; для формы входа можно так
return static::findOne(['access_token' => $token]);
}
Если API-токены вам не нужны, оставлять findIdentityByAccessToken пустым допустимо, но метод должен существовать — интерфейс требует его наличия, иначе будет фатальная ошибка ещё на автозагрузке класса.
validateAuthKey и getAuthKey
Эти два метода отвечают за «запомнить меня» (cookie-based login). Типичная новичковая заглушка возвращает true безусловно:
// так делать нельзя: любой подделанный cookie пройдёт проверку
public function validateAuthKey($authKey)
{
return true;
}
Правильно сверять с сохранённым значением. И заполнять auth_key при создании пользователя, иначе cookie-логин молча не сработает:
public function getAuthKey()
{
return $this->auth_key;
}
public function validateAuthKey($authKey)
{
return $this->auth_key === $authKey;
}
// при регистрации пользователя
public function beforeSave($insert)
{
if (!parent::beforeSave($insert)) {
return false;
}
if ($insert) {
$this->auth_key = Yii::$app->security->generateRandomString();
}
return true;
}
ЕслиenableAutoLoginв конфиге равенtrue, аauth_keyв базе пустой, «запомнить меня» будет вести себя непредсказуемо: галочка есть, а после закрытия браузера пользователь разлогинен. Пустойauth_key— тихий баг, который не даёт ни ошибки, ни лога.
Ошибка 3. Проверка пароля не тем способом
В Yii2 два разных подхода к паролю, и их путают. Хранить нужно хеш, а сравнивать через validatePassword().
// при регистрации — сохраняем хеш, не сам пароль
public function setPassword($password)
{
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
}
// при входе — сверяем введённое с хешем
public function validatePassword($password)
{
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
Частая ошибка — сравнение в лоб: $this->password === $password. Работает на локальной демке с открытыми паролями и разваливается, как только вы переходите на хеши. Обратная ошибка — хранить хеш, но при входе сравнивать строки: тогда правильный пароль никогда не пройдёт, потому что вы сравниваете введённый текст с 60-символьным bcrypt-хешем.
Два способа хранения — сравнение
| Что в базе | Как проверять | Пригодность |
|---|---|---|
| Открытый пароль | === | Только демо из коробки, в прод нельзя |
Хеш generatePasswordHash() | validatePassword() | Рабочий вариант |
Собственный md5/sha1 | ручное сравнение хешей | Небезопасно, не используйте |
Ошибка 4. Логин проходит, но сессия слетает
Вы вызываете Yii::$app->user->login($user), редирект срабатывает, а на защищённой странице снова форма входа. Причины по частоте:
findIdentity()ищет не по первичному ключу. При входе сохраняетсяgetId(), при следующем запросе по этому id вызываетсяfindIdentity(). ЕслиgetId()возвращает id, аfindIdentity()ищет поusername— совпадения не будет.- Нет прав на запись сессий. Каталог сессий PHP недоступен, данные не сохраняются между запросами. Проверьте
session_save_path()и права на него. - Разные домены с www и без. Cookie сессии привязан к домену; логин на
site.ru, редирект наwww.site.ru— сессия теряется. Настройте один канонический хост на уровне сервера.
Проверка первого пункта: временно выведите Yii::$app->user->id сразу после login() и на следующей странице. Если после редиректа там null — проблема в связке getId()/findIdentity().
Ошибка 5. Забытый accessControl и кто вообще залогинен
Аутентификация проверяет, кто вы. Ограничение доступа — отдельная вещь, за неё отвечает AccessControl в behaviors() контроллера. Новички ожидают, что после настройки user страницы сами закроются. Не закроются: без фильтра доступа гость откроет любой экшен.
use yii\filters\AccessControl;
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::class,
'only' => ['profile', 'settings'],
'rules' => [
[
'allow' => true,
'roles' => ['@'], // только авторизованные
],
],
],
];
}
Роль @ — любой залогиненный, ? — гость. Экшены, не попавшие в only, фильтр не трогает вовсе.
Если не получилось
- Class app\models\User must implement yii\web\IdentityInterface — модель не реализует интерфейс или не хватает одного из шести методов. Добавьте
implements \yii\web\IdentityInterfaceи все методы, даже пустые заглушки для токенов. - Форма отправляется, поле не подсвечивает ошибку, но вход не проходит —
validatePassword()сравнивает с пустымpassword_hash. Проверьте, что при регистрации вызывалсяsetPassword(), а не запись пароля напрямую. - После
login()сразу редирект на логин — почти всегда рассинхронgetId()иfindIdentity()(см. Ошибку 4). - Unable to verify your data submission — не относится к паролю, это CSRF-токен: форма отправлена без скрытого поля
_csrf. Стройте форму черезActiveForm, а не голым HTML.
Что настроить дальше
После рабочего входа сразу займитесь двумя вещами. Первое — сброс пароля: механизм с одноразовым токеном на email отдельный от логина, в шаблоне basic его нет, добавляйте руками. Второе — если планируете REST API, доведите до ума findIdentityByAccessToken() и подключите HttpBearerAuth в контроллерах API; это отдельная тема, здесь мы её только обозначаем. И проверьте в проде, что Yii::$app->request->cookieValidationKey задан непустой строкой — без него cookie-логин и CSRF работать не будут.
Репетитор 1—11 класс и ВУЗ: Математика и физика методом наведения на мысль, помощь с ДЗ.
Спросить за 8 ₽Источники: Yii 2.0 Guide — Authentication, Yii 2.0 Guide — Authorization (Access Control Filters)
Частые вопросы
У меня advanced-шаблон, а не basic. Инструкция подойдёт?
Обязательно ли реализовывать findIdentityByAccessToken, если API нет?
Пароль правильный, но validatePassword всегда возвращает false. Почему?
Вход проходит, но после редиректа снова форма логина — что смотреть первым?
Безопасно ли хранить пароли через md5 или sha1, как в старых проектах?
Нужно ли самому проверять авторизацию в каждом экшене?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.