Аутентификация
Аутентификация — проверка того, кто перед нами: посетитель вводит имя и пароль, сайт находит пользователя и запоминает его в сессии. В Yii за это отвечает компонент Yii::$app->user, а сведения о пользователе даёт класс, реализующий интерфейс IdentityInterface.
Что уже есть в проекте
| Файл | Назначение |
|---|---|
models/User.php | Класс пользователя; в шаблоне проекта пользователи записаны прямо в коде |
models/LoginForm.php | Модель формы входа: проверяет имя и пароль |
views/site/login.php | Шаблон формы входа |
controllers/SiteController.php | Действия login и logout |
Страница /site/login уже работает с пользователями admin и demo. Чтобы пользователи хранились в базе, достаточно заменить класс User.
Таблица пользователей
php yii migrate/create create_user_tablepublic function safeUp()
{
$this->createTable('user', [
'id' => $this->primaryKey(),
'username' => $this->string(64)->notNull()->unique(),
'password_hash' => $this->string(255)->notNull(),
'auth_key' => $this->string(32)->notNull(),
]);
}После php yii migrate появится таблица user. Пароль в ней хранится не открытым текстом, а хешем — необратимо преобразованной строкой.
Класс пользователя
Замените содержимое models/User.php:
// models/User.php
namespace app\models;
use Yii;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
public static function findIdentity($id)
{
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return null;
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->auth_key;
}
public function validateAuthKey($authKey)
{
return $this->auth_key === $authKey;
}
public static function findByUsername(string $username): ?self
{
return static::findOne(['username' => $username]);
}
public function validatePassword(string $password): bool
{
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
}Первые пять методов требует интерфейс: по ним Yii находит пользователя по номеру из сессии и проверяет ключ «запомнить меня». Последние два вызывает готовая LoginForm. Класс пользователя указан в config/web.php: 'user' => ['identityClass' => 'app\models\User'].
Создание пользователя
$user = new User();
$user->username = 'anna';
$user->password_hash = Yii::$app->security->generatePasswordHash('secret123');
$user->auth_key = Yii::$app->security->generateRandomString();
$user->save();Выполните этот код один раз, например во временном действии. Теперь на странице /site/login можно войти как anna с паролем secret123.
Вход и выход
Вход выполняет одна строка — она уже есть в LoginForm:
Yii::$app->user->login($user, 3600 * 24 * 30);Второй аргумент — срок в секундах, на который пользователя запомнят после закрытия браузера. Выход — Yii::$app->user->logout().
Текущий пользователь
if (Yii::$app->user->isGuest) {
return $this->redirect(['site/login']);
}
$post->user_id = Yii::$app->user->id;
$name = Yii::$app->user->identity->username;isGuest равно true, пока посетитель не вошёл. id — номер пользователя, identity — объект User. Так при создании статьи записывают её автора.
Частая ошибка
Пароль нельзя хранить открытым текстом и сравнивать через ===: при утечке базы откроются пароли всех пользователей. Записывайте только результат generatePasswordHash() и проверяйте методом validatePassword().