Права доступа
Авторизация отвечает на вопрос «что разрешено этому пользователю»: войти могут все, но изменять статью должен только её автор. В CakePHP права описывают политиками — классами, где каждому действию соответствует метод, возвращающий true или false. Работает с ними плагин Authorization.
Установка
composer require "cakephp/authorization:^3.0"
bin/cake plugin load AuthorizationПлагин опирается на вход из предыдущего урока. У статей должен быть столбец user_id с номером автора — добавьте его миграцией и заполняйте при создании статьи: $article->user_id = $this->request->getAttribute('identity')->getIdentifier();.
Настройка
В src/Application.php добавьте второй интерфейс и метод:
// src/Application.php
use Authorization\AuthorizationService;
use Authorization\AuthorizationServiceInterface;
use Authorization\AuthorizationServiceProviderInterface;
use Authorization\Middleware\AuthorizationMiddleware;
use Authorization\Policy\OrmResolver;
public function getAuthorizationService(ServerRequestInterface $request): AuthorizationServiceInterface
{
return new AuthorizationService(new OrmResolver());
}В списке implements класса дописывают AuthorizationServiceProviderInterface. OrmResolver находит политику по классу записи: для Article — ArticlePolicy.
В методе middleware() добавьте строку после AuthenticationMiddleware:
->add(new AuthorizationMiddleware($this))И подключите компонент в AppController::initialize():
$this->loadComponent('Authorization.Authorization');Политика
Политики лежат в папке src/Policy:
bin/cake bake policy --type entity Article// src/Policy/ArticlePolicy.php
namespace App\Policy;
use App\Model\Entity\Article;
use Authorization\IdentityInterface;
class ArticlePolicy
{
public function canEdit(IdentityInterface $user, Article $article): bool
{
return $article->user_id === $user->getIdentifier();
}
}Метод canEdit() отвечает за действие edit: изменять статью может только её автор. Для удаления пишут canDelete() и так далее.
Проверка в действии
// src/Controller/ArticlesController.php
public function edit(int $id)
{
$article = $this->Articles->get($id);
$this->Authorization->authorize($article);
// дальше — обычная обработка формы
}authorize() вызывает метод политики с именем текущего действия. Войдите под другим пользователем и откройте чужую статью на изменение — вместо формы появится ошибка 403.
Действия без проверки
Плагин требует, чтобы каждое действие либо проверило права, либо явно отказалось от проверки:
public function index(): void
{
$this->Authorization->skipAuthorization();
$this->set('articles', $this->paginate($this->Articles->find()));
}Проверка без ошибки
| Где | Вызов |
|---|---|
| В действии | $this->Authorization->can($article, 'edit') |
| В шаблоне | $this->request->getAttribute('identity')->can('edit', $article) |
Оба вызова возвращают true или false. Так в шаблоне прячут ссылку «Изменить» от тех, кому она недоступна:
<p>
<?php if ($this->request->getAttribute('identity')->can('edit', $article)): ?>
<?= $this->Html->link('Изменить', ['action' => 'edit', $article->id]) ?>
<?php endif; ?>
</p>Частая ошибка
Действие, в котором нет ни authorize(), ни skipAuthorization(), заканчивается исключением о том, что проверка прав не выполнена. Это защита от забытых проверок, а не поломка: добавьте в действие один из двух вызовов.