📜 ⬆️ ⬇️

Yii2-advanced: Flexible configuration of Yii2 RBAC (roles, permissions, rules)

The admin may not have access to the user's permissions and within the same role users may have different access to permissions.


How to organize entities Role, Permission, Rule


Roles: role types supper_admin, admin, customer (employee, manager), user (authorized user), guest (unauthorized user). The supper_admin role inherits permissions from all roles, thanks to this, supper_admin has access to all permission regardless of their presence in a particular role, but a pass is required in all rules;

Permission: the role is the direct parent of the permission, without inheritance (except the role supper_admin). In other words, the same permission will be assigned to each desired role.
Rules (Rule): rules for roles and permissions are inherited from BaseRole where there is a check of general rules.

You will need to encode the admin panel for roles, permissions, user permissions.
What should be there:
Admin for roles.
Add, delete, update permissions.
')
Admin for permissions.
Add, remove.

Admin permission user.
It should be possible for a specific user to assign or remove a certain permission or prohibiting permission. Further explanation will be given about the prohibition permissions.

 : 'components' => [ .... 'authManager' => [ 'class' => 'yii\rbac\DbManager', 'itemTable' => 'auth_item', 'itemChildTable' => 'auth_item_child', 'assignmentTable' => 'auth_assignment', 'ruleTable' => 'auth_rule', 'defaultRoles' => ['guest'],//        ], ....] 

The main thing is to find a place in the project where the check will be located, since the names of the permissions depend on it and they will be checked.

The easiest way is to generate permission keys from the action controller to which we fall. You can add to the dongle this key or the front-end part, the controller name and the request method and method GET, POST, PUT, DELETE ... to form a unique name for the permission throughout the site . For example, fr_user_profile_get for the frontend site.com.ua/user/profile using the GET method

Click the link below for information on the location of the access check:
Alternative RBAC setting

Method 1 - in the controller method
 public function actionIndex() { if (!\Yii::$app->user->can('index')) { throw new ForbiddenHttpException('Access denied'); } return $this->render('index'); } 


Method 2 - register beforeAction
 public function beforeAction($action) { if (parent::beforeAction($action)) { if (!\Yii::$app->user->can($action->id)) { throw new ForbiddenHttpException('Access denied'); } return true; } else { return false; } } 


So, you have already decided on the place where permission is checked. Now we will organize logic.

To allow a specific user to deny a certain permission, we create the permission and call the name of the permission with the _not postprefix which, if the user has, will deny access, and the check for this permission will occur in the basic rule from which all rules for roles and permissions are inherited.

Permission check


 /*                   / */ if(!Yii::$app->user->can( '  ',['class'=>static::class])){ throw new \yii\web\ForbiddenHttpException('Access denied role '); } 

Starting the creation of roles and rules
 // RULES Yii::$app->authManager->removeAllRules(); //           $BaseRule= new \common\rbac\BaseRule(); Yii::$app->authManager->add($BaseRule); //   $RuleUpdateDelete=new \common\rbac\RuleUpdateDelete(); Yii::$app->authManager->add($RuleUpdateDelete); //     admin $RuleForAdmin= new \common\rbac\RuleForAdmin(); Yii::$app->authManager->add($RuleForAdmin); //     customer $RuleForCustomer= new \common\rbac\RuleForCustomer(); Yii::$app->authManager->add($RuleForCustomer); //     user $RuleForUser= new \common\rbac\RuleForUser(); Yii::$app->authManager->add($RuleForUser); //     guest $RuleForGuest= new \common\rbac\RuleForGuest(); Yii::$app->authManager->add($RuleForGuest); // ROLES Yii::$app->authManager->removeAllRoles(); $role_supper_admin = Yii::$app->authManager->createRole('supper_admin'); $role_supper_admin->description='supper_admin'; Yii::$app->authManager->add($role_supper_admin); $role_admin = Yii::$app->authManager->createRole('admin'); $role_admin->description=' admin'; $role_admin->ruleName=$RuleForAdmin->name; Yii::$app->authManager->add($role_admin); $role_customer = Yii::$app->authManager->createRole('customer'); $role_customer->description=' customer'; $role_customer->ruleName=$RuleForCustomer->name; Yii::$app->authManager->add($role_customer); $role_user = Yii::$app->authManager->createRole('user');//  $role_user->description=' '; $role_user->ruleName=$RuleForUser->name; Yii::$app->authManager->add($role_user); $role_guest = Yii::$app->authManager->createRole('guest');//   $role_guest->description='  '; $role_guest->ruleName=$RuleForGuest->name; Yii::$app->authManager->add($role_guest); //     Yii::$app->authManager->addChild($role_supper_admin, $role_admin); Yii::$app->authManager->addChild($role_supper_admin, $role_customer); Yii::$app->authManager->addChild($role_supper_admin, $role_user); Yii::$app->authManager->addChild($role_supper_admin, $role_guest); 


When creating a role, consider


create
  public function create(){ //            $BaseRule= new BaseRule(); $role_new = Yii::$app->authManager->createRole($this->role); $role_new->description=$this->description; if($this->data)$role_new->data=$this->data; //          $role_new->ruleName=$BaseRule->name; Yii::$app->authManager->add($role_new); //   if($role_new=Yii::$app->authManager->getRole($this->role)){ if(isset($this->permissions)){ foreach ($this->permissions as $permission=>$val){ $child= Yii::$app->authManager->getPermission($permission); if($child instanceof yii\rbac\Permission && Yii::$app->authManager->canAddChild($role_new, $child)) { Yii::$app->authManager->addChild($role_new, $child); } } } //      supper_admin         $role_supper_admin=Yii::$app->authManager->getRole('supper_admin'); if(Yii::$app->authManager->canAddChild($role_supper_admin, $role_new)){ Yii::$app->authManager->addChild($role_supper_admin, $role_new); } return true; }else{ return false; } } 


When creating permission to take into account


create
  public function create() { /*        $this->permission               /     .                      (..                  supper_admin,admin,customer)  $permission->data                  . */ if(preg_match('#.*(Delete|Put)$#', $this->method) ){ $Rule=Yii::$app->authManager->getRule('RuleUpdateDelete'); }else{ $Rule=Yii::$app->authManager->getRule('BaseRule'); } $permission = Yii::$app->authManager->createPermission($this->permission); $permission->description = $this->description; //          $permission->ruleName = $Rule->name; $permission->data = [....];//    Yii::$app->authManager->add($permission); // -   _not $permission_not = Yii::$app->authManager->createPermission($this->permission.'_not'); $permission_not ->description = '   '.$this->permission; Yii::$app->authManager->add($permission_not ); //   gr_auth_item  isnot   permission return Yii::$app->db->createCommand("UPDATE `gr_auth_item` SET `isnot`= 1 WHERE type=2 AND name=:name") ->bindValue(":name", $this->permission.'_not',PDO::PARAM_STR) ->execute(); } 


Basic rule


BaseRule
 /*    supper_admin   ,      */ class BaseRule extends \yii\rbac\Rule { public $name ='BaseRule'; public function execute($user_id, $permission, $params) { if(Yii::$app->user->can('supper_admin') )return 1; //       if(Yii::$app->user->can($permission->name.'_not') )return false; //   admin  manager     return true; } } 


Basic role rule


RuleForUser
 //    (     supper_admin) //       ...->can('user') //   user /*            BaseRule */ class RuleForUser extends BaseRule { public $name='RuleForUser' ; public function execute($user_id, $role, $params) { $parent= parent::execute($user_id, $role, $params); if($parent===1)return true; if($parent==false)return false; if(isset(Yii::$app->authManager->getRolesByUser($user_id)[$role->name]))return true; return false; } } 


Rule requiring change check


RuleUpdateDelete
 /*       BaseRule */ class RuleUpdateDelete extends BaseRule { public $name = 'RuleUpdateDelete' ; public function execute($user_id, $permission, $params) { //    $parent= parent::execute($user_id, $permission, $params); if($parent===1)return true; if($parent==false)return false; //     admin  customer if(Yii::$app->user->can('admin') || Yii::$app->user->can('customer'))return true; if(isset($params['class']) && method_exists($params['class'], 'can') ){ //       if(method_exists($params['class'], 'can')) return $params['class']::can($user_id); else return false; } return false; } } 

What work does the $ params parameter do in the execute method?
When we perform the check
 if(!Yii::$app->user->can( '  ',['class'=>static::class])){ throw new \yii\web\ForbiddenHttpException('Access denied role '); } 

we pass the second parameter to the array. In my case, this is the class that I use to call the can method of the same name in this class to verify that a particular user belongs to the object being changed.

Total


You should get the functionality with which you can flexibly manage the rights and access to the entire site, be able to gain full access without restrictions with the supper_admin role, flexibly adjust permissions for specific users.

good luck, Jekshmek

Source: https://habr.com/ru/post/327170/


All Articles