Когда ваш проект на Yii2 вырастает из песочницы, возникает вопрос: как сделать так, чтобы каждый пользователь видел только то, что ему положено? Базовая аутентификация не справляется, а права "админ-не админ" — это как светофор с двумя цветами. Тут на сцену выходит RBAC (Role-Based Access Control) — управление доступом на основе ролей. В этой статье я покажу, как построить расширенную систему RBAC, которая не сломается, когда у вас появится сто ролей и тысяча разрешений.

Что такое RBAC и зачем он нужен

RBAC — это как гардеробная в театре: у каждого актёра есть свой костюм (роль), и он может заходить только в те комнаты, которые соответствуют его костюму. В Yii2 это реализовано через иерархию ролей, разрешений и правил. Простыми словами: роль — это группа прав, а разрешение — конкретное действие (например, "редактировать статью"). Правила — это дополнительные фильтры, которые проверяют, может ли пользователь выполнить действие в данный момент.

Зачем это нужно? Чтобы не писать сотни if-else по всему коду. Чтобы можно было быстро добавить нового модератора, не переписывая логику. Чтобы безопасность была на уровне, а не на честном слове.

Настройка компонента authManager

Первым делом нужно включить RBAC в Yii2. Откройте файл конфигурации (обычно config/web.php или config/main.php) и добавьте компонент authManager. Выберите способ хранения: файловый (простой, но не для продакшена) или база данных (рекомендую). Вот пример настройки для БД:

'components' => [
    'authManager' => [
        'class' => 'yii\rbac\DbManager',
    ],
],

После этого выполните миграцию для создания таблиц RBAC. В Yii2 есть встроенная миграция. Запустите в консоли:

yii migrate --migrationPath=@yii/rbac/migrations

Эта команда создаст четыре таблицы: auth_item (роли и разрешения), auth_item_child (связи между ними), auth_assignment (назначение ролей пользователям) и auth_rule (правила). Теперь фундамент готов.

Создание ролей и разрешений: первый этап

Теперь нужно наполнить систему. Обычно это делается в консольной команде или миграции. Создадим базовые роли: user, moderator, admin. И разрешения: createPost, updatePost, deletePost.

$auth = Yii::$app->authManager;

// Создаем роли
$user = $auth->createRole('user');
$moderator = $auth->createRole('moderator');
$admin = $auth->createRole('admin');

// Создаем разрешения
$createPost = $auth->createPermission('createPost');
$updatePost = $auth->createPermission('updatePost');
$deletePost = $auth->createPermission('deletePost');

// Добавляем в систему
$auth->add($user);
$auth->add($moderator);
$auth->add($admin);
$auth->add($createPost);
$auth->add($updatePost);
$auth->add($deletePost);

// Назначаем разрешения ролям
$auth->addChild($user, $createPost);
$auth->addChild($moderator, $updatePost);
$auth->addChild($admin, $deletePost);
$auth->addChild($admin, $moderator); // admin наследует права moderator
$auth->addChild($moderator, $user); // moderator наследует права user

Обратите внимание: addChild создаёт иерархию. Админ получает все права модератора и пользователя. Это мощный механизм, но будьте осторожны: случайное наследование может открыть доступ туда, где не нужно.

Расширенные возможности: правила и бизнес-логика

Просто ролей и разрешений часто мало. Например, пользователь может редактировать только свои посты. Тут в игру вступают правила (rules). Правило — это класс, который реализует интерфейс yii\rbac\Rule. Он проверяет, можно ли выполнить действие в контексте.

class AuthorRule extends \yii\rbac\Rule
{
    public $name = 'isAuthor';

    public function execute($user, $item, $params)
    {
        return isset($params['post']) ? $params['post']->created_by == $user : false;
    }
}

Теперь привяжем правило к разрешению updateOwnPost:

$auth = Yii::$app->authManager;

$rule = new AuthorRule();
$auth->add($rule);

$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);

// Назначаем пользователю
$auth->addChild($user, $updateOwnPost);

Правила можно комбинировать. Например, правило "isAuthor" плюс разрешение "updatePost" дадут возможность редактировать только свои посты, а не чужие. Это как ключ от квартиры: он подходит только к вашей двери.

Проверка прав в контроллерах и представлениях

Когда система настроена, нужно её использовать. Самый простой способ — через Yii::$app->user->can(). В контроллере это выглядит так:

public function actionUpdate($id)
{
    $post = Post::findOne($id);
    if (!Yii::$app->user->can('updatePost', ['post' => $post])) {
        throw new \yii\web\ForbiddenHttpException('Доступ запрещен');
    }
    // логика обновления
}

В представлениях можно скрывать кнопки:

if (Yii::$app->user->can('updatePost', ['post' => $model])) {
    echo Html::a('Редактировать', ['update', 'id' => $model->id]);
}

Для глобальной проверки используйте фильтры доступа (AccessControl) в поведении контроллера:

public function behaviors()
{
    return [
        'access' => [
            'class' => \yii\filters\AccessControl::class,
            'rules' => [
                [
                    'allow' => true,
                    'roles' => ['@'], // только авторизованные
                ],
                [
                    'allow' => true,
                    'actions' => ['create'],
                    'permissions' => ['createPost'], // проверка разрешения
                ],
            ],
        ],
    ];
}
Лайфхак: Не проверяйте роли напрямую в коде (например, Yii::$app->user->identity->role == 'admin'). Это убивает гибкость. Всегда используйте разрешения. Тогда, если завтра роль админа переименуют, ваш код не сломается.

Таблица сравнения способов хранения

СпособПлюсыМинусы
PhpManager (файлы)Простота, не требует БДНе подходит для продакшена, нет миграций
DbManager (БД)Гибкость, поддержка миграций, масштабированиеТребует настройки БД

Я всегда выбираю DbManager. Даже для мелких проектов — привычка, которая спасает, когда проект внезапно становится большим.

Советы по расширению системы

  • Группируйте разрешения. Создайте промежуточные роли, например, editor (редактор контента) и manager (управление пользователями). Это упростит иерархию.
  • Используйте кэширование. RBAC-запросы могут быть частыми. Включите кэш для authManager в конфиге: добавьте свойство cache с компонентом кэша.
  • Не злоупотребляйте правилами. Сложные правила замедляют систему. Если правило проверяет что-то тяжёлое (например, запрос к внешнему API), подумайте о кэшировании результата.
  • Документируйте роли. Когда ролей станет много, без документации вы запутаетесь. Ведите список в комментариях к миграциям.

Что в итоге

RBAC в Yii2 — это не rocket science. Вы настроили компонент, создали роли и разрешения, добавили правила для бизнес-логики и теперь проверяете права в контроллерах. Система стала гибкой: вы можете добавить новую роль за пять минут, не трогая код. Главное — не ленитесь и не используйте хардкод. Помните: хорошая система прав — это как хороший фундамент: его не видно, но на нём всё держится.

Студия WNDER