RBAC в Yii2 без хаоса: роли, разрешения и проверка доступа
RBAC в Yii2 часто начинают настраивать с ролей: admin, manager, editor, operator. Через несколько месяцев появляются роли manager2, senior_manager, admin_without_delete, content_plus_orders. В какой-то момент уже никто не понимает, кто что может делать и почему.
Проблема обычно не в Yii2, а в том, что роли смешали с конкретными сотрудниками и не выделили разрешения как отдельные действия.
Сначала разрешения, потом роли
Разрешение должно описывать действие, а не должность. Например:
- order.view;
- order.update;
- order.delete;
- product.import;
- user.manage;
- settings.update.
Роль — это набор разрешений. Так проще объяснить систему: менеджер может смотреть и менять заказы, но не может удалять пользователей или менять настройки интеграций.
Не создавать роль под каждого человека
Если у каждого сотрудника отдельная роль, RBAC быстро превращается в ручной список исключений. Лучше иметь несколько рабочих ролей и отдельные permissions для редких действий.
Если одному человеку временно нужен доступ, это повод либо выдать отдельное разрешение, либо пересмотреть процесс. Но не стоит плодить роли ради одного случая.
Миграции прав
Права должны создаваться кодом, а не только руками в админке. Тогда стенды и production будут одинаковыми.
public function safeUp()
{
$auth = Yii::$app->authManager;
$viewOrders = $auth->createPermission('order.view');
$viewOrders->description = 'Просмотр заказов';
$auth->add($viewOrders);
$manager = $auth->createRole('manager');
$manager->description = 'Менеджер';
$auth->add($manager);
$auth->addChild($manager, $viewOrders);
}
Если права создаются через миграции, легче понять, когда и зачем они появились.
Проверка доступа в коде
Проверки лучше делать через can(), а не через жёсткую проверку роли.
if (!Yii::$app->user->can('order.update')) {
throw new \yii\web\ForbiddenHttpException('Недостаточно прав');
}
Плохой вариант:
if (Yii::$app->user->identity->role !== 'admin') {
// запретить
}
Такой код быстро ломает гибкость. Потом появится руководитель, которому нужно редактировать заказы, но он не admin.
AccessControl
Для контроллеров можно использовать AccessControl, но его не нужно превращать в единственное место безопасности. Важные действия лучше дополнительно проверять внутри action или service.
public function behaviors()
{
return [
'access' => [
'class' => \yii\filters\AccessControl::class,
'rules' => [
[
'allow' => true,
'actions' => ['update'],
'roles' => ['order.update'],
],
],
],
];
}
Права на объект
Иногда мало знать, что пользователь может редактировать заказы вообще. Нужно проверить, может ли он редактировать конкретный заказ: свой, своего отдела, своего склада.
if (!Yii::$app->user->can('order.update', ['order' => $order])) {
throw new \yii\web\ForbiddenHttpException();
}
Для этого используют rules. Это уже не просто роль, а проверка контекста.
Логировать отказ доступа
Если пользователь регулярно получает 403, это может быть ошибка настройки, а может быть попытка доступа не туда. Полезно логировать важные отказы.
Yii::warning([
'user_id' => Yii::$app->user->id,
'permission' => 'order.delete',
'order_id' => $orderId,
], 'access');
Чек-лист
- Описать permissions как действия.
- Собрать роли из permissions.
- Не создавать роли под каждого сотрудника.
- Создавать права через миграции.
- Проверять доступ через Yii::$app->user->can().
- Не завязывать код на имя роли admin.
- Для важных сущностей проверять доступ к конкретному объекту.
- Логировать важные отказы доступа.
Хороший RBAC скучный. В нём мало ролей, понятные разрешения и нет специальных условий, спрятанных по контроллерам. Если права можно объяснить без открытия кода, структура выбрана правильно.
Комментарии (0)
Пока нет комментариев. Будьте первым!