Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Права доступа

Авторизация отвечает на вопрос «что разрешено этому пользователю»: войти могут все, но изменять статью должен только её автор. В 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(), заканчивается исключением о том, что проверка прав не выполнена. Это защита от забытых проверок, а не поломка: добавьте в действие один из двух вызовов.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.