Вход на сайт
Аутентификация — проверка того, кто перед нами: посетитель вводит почту и пароль, сайт запоминает его в сессии. В CakePHP этим занимается официальный плагин Authentication. Плагин — отдельный пакет, расширяющий фреймворк.
Установка
composer require "cakephp/authentication:^3.0"
bin/cake plugin load AuthenticationПервая команда скачивает пакет, вторая включает его в проекте.
Таблица пользователей
bin/cake bake migration CreateUsers email:string:unique password:string created modified
bin/cake migrations migrate
bin/cake bake all UsersПоявятся таблица users, модель, контроллер UsersController и шаблоны — в том числе форма регистрации /users/add.
Хеш пароля
Пароль нельзя хранить открытым текстом. Добавьте в класс записи метод, который хеширует его при каждом присваивании:
// src/Model/Entity/User.php
use Authentication\PasswordHasher\DefaultPasswordHasher;
protected function _setPassword(string $password): ?string
{
return $password !== '' ? (new DefaultPasswordHasher())->hash($password) : null;
}Метод с приставкой _set вызывается при записи в поле. Зарегистрируйте пользователя на /users/add — в базе окажется длинная строка хеша.
Настройка
Плагин настраивают в src/Application.php. Класс должен реализовать интерфейс и получить новый метод:
// src/Application.php
use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Psr\Http\Message\ServerRequestInterface;
class Application extends BaseApplication implements AuthenticationServiceProviderInterface
{
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$service = new AuthenticationService([
'unauthenticatedRedirect' => '/users/login',
'queryParam' => 'redirect',
]);
$fields = ['username' => 'email', 'password' => 'password'];
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => '/users/login',
]);
$service->loadIdentifier('Authentication.Password', ['fields' => $fields]);
return $service;
}
}Session узнаёт уже вошедшего пользователя, Form проверяет отправленную форму входа. В методе middleware() того же файла добавьте строку после RoutingMiddleware:
->add(new AuthenticationMiddleware($this))И подключите компонент в AppController::initialize():
$this->loadComponent('Authentication.Authentication');С этого момента все страницы требуют входа: гостя перенаправляет на /users/login.
Вход и выход
// src/Controller/UsersController.php
public function beforeFilter(\Cake\Event\EventInterface $event): void
{
parent::beforeFilter($event);
$this->Authentication->allowUnauthenticated(['login', 'add']);
}
public function login()
{
$result = $this->Authentication->getResult();
if ($result && $result->isValid()) {
return $this->redirect($this->Authentication->getLoginRedirect() ?? '/');
}
if ($this->request->is('post')) {
$this->Flash->error('Неверная почта или пароль.');
}
}
public function logout()
{
$this->Authentication->logout();
return $this->redirect(['action' => 'login']);
}Почту и пароль проверяет сам плагин — действию остаётся посмотреть на результат. allowUnauthenticated() открывает перечисленные действия гостям.
Форма входа
Создайте templates/Users/login.php:
<h1>Вход</h1>
<?= $this->Form->create() ?>
<?= $this->Form->control('email', ['label' => 'Почта']) ?>
<?= $this->Form->control('password', ['label' => 'Пароль']) ?>
<?= $this->Form->button('Войти') ?>
<?= $this->Form->end() ?>Откройте /articles — вас перенаправит на форму входа, а после входа вернёт обратно.
Текущий пользователь
$user = $this->request->getAttribute('identity');
$userId = $user->getIdentifier();
$email = $user->email;Атрибут identity содержит вошедшего пользователя или null для гостя.
Частая ошибка
После подключения плагина закрытыми становятся все страницы, включая саму страницу входа. Если не открыть её через allowUnauthenticated(['login']), гость попадёт в бесконечное перенаправление. Публичные страницы — список и просмотр статей — открывают так же в beforeFilter() своего контроллера.