RBAC в Yii2: как настроить роли и разрешения правильно
Роли, разрешения и правила в Yii2 через authManager. Разбираем, когда хватает простой проверки, а когда нужны бизнес-правила, и на чём чаще всего спотыкаются при переходе с ролей в базе на кэш.

Разработчики на Yii2 регулярно совершают одну и ту же ошибку: раскидывают проверки прав по контроллерам через if ($user->role == 'admin'), а через полгода не могут найти все места, где решается, кто и что может делать. Yii2 из коробки даёт полноценный RBAC (role-based access control) — систему ролей, разрешений и правил, которая централизует эту логику. Разберём, как её собрать так, чтобы через год не переписывать.
Материал для Yii 2.0.4x — API authManager стабилен с ранних версий 2.0. Заранее решите, где хранить назначения: в файлах (PhpManager) или в базе (DbManager). Это решение потом дорого менять.
Три сущности, из которых всё состоит
RBAC в Yii оперирует тремя типами объектов, и путаница между ними — источник большинства проблем.
- Разрешение (permission) — атомарное действие:
createPost,deletePost,updateOwnPost. Проверяется в коде черезYii::$app->user->can('createPost'). - Роль (role) — набор разрешений:
author,moderator,admin. Роль назначается пользователю. - Правило (rule) — класс, который решает динамический вопрос: например, «это его собственный пост». Правило прикрепляется к разрешению или роли.
Роли и разрешения связаны в иерархию: роль наследует разрешения, разрешения могут вкладываться в другие разрешения. Проверка can() обходит этот граф.
Главная мысль RBAC в Yii: контроллер не должен знать названий ролей. Он спрашивает «можно ли выполнить это действие», а не «ты админ». Роли — деталь конфигурации, которая меняется без правки контроллеров.
PhpManager или DbManager: что выбрать
Yii предлагает два хранилища назначений. Выбор влияет на всё остальное.
| Критерий | PhpManager | DbManager |
|---|---|---|
| Где хранит | PHP-файлы в @app/rbac | Таблицы в БД |
| Назначение ролей пользователям | В файле, статично | Через код в рантайме |
| Подходит для | Фиксированный набор ролей, назначаемых редко | Пользователи сами получают роли (регистрация, покупка подписки) |
| Производительность | Читает файлы при каждом запросе | Запросы к БД, лечится кэшем |
Если у вас блог, где роли выдаёт только суперадмин — PhpManager. Если пользователи получают права динамически (продавец после модерации, подписчик после оплаты) — только DbManager.
Настройка DbManager
Сначала подключите компонент в конфигурации приложения. Для консольного и веб-приложения — в обоих, иначе миграции RBAC не запустятся.
// config/web.php и config/console.php
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',
// кэш ускоряет can() в разы, не пропускайте
'cache' => 'cache',
],
],Затем создайте таблицы RBAC встроенной миграцией:
php yii migrate --migrationPath=@yii/rbac/migrationsПосле выполнения в базе появятся таблицы auth_item, auth_item_child, auth_assignment и auth_rule. Проверка: команда завершилась без ошибок и вывела Migrated up successfully.
Наполнение через консольную команду, а не руками
Роли и разрешения нельзя держать «в голове». Опишите их в консольной команде или миграции — тогда структура прав версионируется в git и воспроизводится на любом окружении.
<?php
// commands/RbacController.php
namespace app\commands;
use Yii;
use yii\console\Controller;
use app\rbac\OwnerRule;
class RbacController extends Controller
{
public function actionInit()
{
$auth = Yii::$app->authManager;
// очищаем перед пересборкой, чтобы избежать дублей
$auth->removeAll();
// разрешения
$createPost = $auth->createPermission('createPost');
$createPost->description = 'Создание поста';
$auth->add($createPost);
$updatePost = $auth->createPermission('updatePost');
$updatePost->description = 'Редактирование любого поста';
$auth->add($updatePost);
// правило "владелец записи"
$ownerRule = new OwnerRule();
$auth->add($ownerRule);
// разрешение с правилом: редактировать только свой пост
$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->description = 'Редактирование своего поста';
$updateOwnPost->ruleName = $ownerRule->name;
$auth->add($updateOwnPost);
// updateOwnPost наследует updatePost, но с ограничением правила
$auth->addChild($updateOwnPost, $updatePost);
// роли
$author = $auth->createRole('author');
$auth->add($author);
$auth->addChild($author, $createPost);
$auth->addChild($author, $updateOwnPost);
$admin = $auth->createRole('admin');
$auth->add($admin);
$auth->addChild($admin, $updatePost);
$auth->addChild($admin, $author);
echo "RBAC инициализирован\n";
}
}Запуск: php yii rbac/init. Теперь admin наследует всё от author плюс безусловное updatePost, а author может править только свои посты через правило.
Правило «владелец записи»
Правило — это класс, наследник yii\rbac\Rule с методом execute. Именно здесь живёт динамическая логика, которую нельзя выразить статичной иерархией.
<?php
// rbac/OwnerRule.php
namespace app\rbac;
use yii\rbac\Rule;
class OwnerRule extends Rule
{
public $name = 'isOwner';
/**
* $user — id пользователя
* $item — роль или разрешение, к которому привязано правило
* $params — то, что передали третьим аргументом в can()
*/
public function execute($user, $item, $params)
{
// ожидаем в params модель поста
return isset($params['post'])
? $params['post']->author_id == $user
: false;
}
}Ключевой момент: правило получает $params из вызова can(). Без передачи модели правило вернёт false, и автор не сможет отредактировать даже свой пост.
Проверка в контроллере
В контроллере проверяем разрешение, а не роль. Модель передаётся третьим аргументом, чтобы правило получило контекст.
public function actionUpdate($id)
{
$post = $this->findModel($id);
if (!Yii::$app->user->can('updateOwnPost', ['post' => $post])) {
throw new \yii\web\ForbiddenHttpException(
'Вы не можете редактировать этот пост.'
);
}
// дальше обычная логика обновления
}Админ пройдёт проверку через безусловное updatePost, автор — через updateOwnPost с правилом, чужой пользователь получит 403.
Автоматизация через AccessControl и фильтры
Прописывать can() в каждом действии утомительно. Для действий без бизнес-правил используйте AccessControl в behaviors() контроллера — он проверяет разрешение до входа в действие. Для действий, где нужен контекст объекта (как updateOwnPost), проверку всё равно оставляйте внутри действия: фильтр не имеет доступа к загруженной модели.
Когда выносить в фильтр, а когда оставлять в действии
- В
AccessControl— статичные разрешения:viewAdminPanel,createPost. Нет зависимости от конкретной записи. - Внутри действия — всё, что требует
$paramsс моделью: «свой пост», «заказ моего магазина», «участник этого проекта».
Где RBAC в Yii ломается
Типичные грабли, на которые наступают при боевом использовании.
- Кэш не сбрасывается после
rbac/init. Если задан параметрcache, старая иерархия остаётся в памяти. После пересборки ролей чистите кэш приложения, иначе проверки идут по устаревшему графу. - Правило возвращает
falseиз-за забытых$params. Самая частая причина «автор не может править свой пост» — модель не передали вcan(). - Проверка роли по имени вместо разрешения.
can('admin')сработает, но привязывает контроллер к названию роли. Переименуете роль — сломаются проверки. Всегда проверяйте разрешение. - Гость и
can(). Для неавторизованного пользователяuser->idравенnull, назначений нет,can()вернётfalse. Для публичных прав используйтеdefaultRoles— роль, которая назначается всем автоматически.
Что настроить дальше
После рабочей базовой схемы посмотрите на defaultRoles в конфигурации authManager — через них удобно раздать гостю и любому авторизованному минимальный набор прав без явного назначения. Если ролей становится много и админам нужно управлять ими из интерфейса, разверните готовое расширение с UI поверх DbManager, но структуру прав всё равно держите в версионируемой консольной команде. Следующая отдельная тема — производительность can() под нагрузкой и прогрев кэша RBAC; здесь мы её не разворачивали.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: Yii2 Guide — Authorization (RBAC), Yii2 API — yii\rbac\DbManager
Частые вопросы
Что делать, если после rbac/init автор всё равно не может редактировать свой пост?
У меня Yii 2.0.15, а не свежая версия — код подойдёт?
Можно ли начать с PhpManager, а потом перейти на DbManager?
Как проверять права для гостя (неавторизованного пользователя)?
Обязательно ли писать правила (Rule), или можно обойтись ролями?
Почему нельзя просто писать if ($user->role == 'admin') в контроллере?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.