mysql - Yii2 RBAC Multiple Assignments for Each User Based on Groups -


my application technically has 2 areas, global area (feedback, user profile, user settings, etc) , group area (contacts, projects, group profile, group settings, etc).

i using rbac dbmanager global area, , works fine, having issues implementing authorization mechanism group area.

the reason, groups can shared among users, , user may have multiple assignments in group_access table (id, group_id, user_id, item_name) may members of multiple groups, , may have different permission levels groups.

here auth setup:

$auth = yii::$app->authmanager;      // group permissions     $managegroupusers = $auth->createpermission('manage_group_users');     $managegroupusers->description = 'manage group users';     $auth->add($managegroupusers);      $managegroupsettings = $auth->createpermission('manage_group_settings');     $managegroupsettings->description = 'manage group settings';     $auth->add($managegroupsettings);      // app permissions     $manageappusers = $auth->createpermission('manage_app_users');     $manageappusers->description = 'manage app users';     $auth->add($manageappusers);      $manageappgroups = $auth->createpermission('manage_app_groups');     $manageappgroups->description = 'manage app groups';     $auth->add($manageappgroups);      $manageappsettings = $auth->createpermission('manage_app_settings');     $manageappsettings->description = 'manage app settings';     $auth->add($manageappsettings);      $manageappfeedback = $auth->createpermission('manage_app_feedback');     $manageappfeedback->description = 'manage app feedback';     $auth->add($manageappfeedback);      // group roles     // -- create role     $groupuser = $auth->createrole('group_user');     $groupuser->description = 'group users';     $auth->add($groupuser);      // -- create role     $groupadmin = $auth->createrole('group_admin');     $groupadmin->description = 'group administrators';     $auth->add($groupadmin);     // add permissions     $auth->addchild($groupadmin, $managegroupusers);     $auth->addchild($groupadmin, $managegroupsettings);     // inherit permissions     $auth->addchild($groupadmin, $groupuser);      // -- create role     $groupcreator = $auth->createrole('group_creator');     $groupcreator->description = 'group creators';     $auth->add($groupcreator);     // inherit permissions     $auth->addchild($groupcreator, $groupadmin);      // app roles     // -- create role     $appuser = $auth->createrole('app_user');     $appuser->description = 'app users';     $auth->add($appuser);      // -- create role     $appsupport = $auth->createrole('app_support');     $appsupport->description = 'support users';     $auth->add($appsupport);     // add permissions     $auth->addchild($appsupport, $manageappfeedback);      // -- create role     $appadmin = $auth->createrole('app_admin');     $appadmin->description = 'app administrators';     $auth->add($appadmin);     // add permissions     $auth->addchild($appadmin, $manageappusers);     $auth->addchild($appadmin, $manageappgroups);     $auth->addchild($appadmin, $manageappsettings);     // inherit permissions     $auth->addchild($appadmin, $appuser);     $auth->addchild($appadmin, $appsupport);      // -- create role     $appcreator = $auth->createrole('app_creator');     $appcreator->description = 'app creators';     $auth->add($appcreator);     // inherit permissions     $auth->addchild($appcreator, $appadmin); 

my group_access table has same schema auth_assignment table, exception has group_id column, , user_id column not unique.

the user have 1 assignment concerning global area, may have many different assigments on group area might have admin privelidges on group a, user privielidges on group b.

my db set like:

  1. users (status_id, username, auth_key, password_hash, email, etc)

  2. groups (status_id, name, description, etc)

  3. group_access (group_id, user_id, item_name) each user gets 1 assignment each group have access to.

    sample_group_access_records [ [ 'id' => 1, 'user_id' => 35, 'group_id' => 17, 'item_name' => 'group_admin' ], [ 'id' => 2, 'user_id' => 35, 'group_id' => 356, 'item_name' => 'group_user' ], [ 'id' => 3, 'user_id' => 35, 'group_id' => 211, 'item_name' => 'group_creator' ], ];

the checkaccess function can qualify userid, , can use shorter "can" version works great logged in user, need check access based on user option below:

option::getoption('user', 'active_group_id') 

this custom function pulls active group id user options table. if user switches groups, changed. options model has 3 types 'app', 'user', 'group'.

it nice if figure out function works same native checkaccess called checkgroupaccess , automatically active_group_id , pull user assignments group_access table , perform permission check.

i hope makes sense.

thank time.

mike

** updated **

so, have solution, uses custom checkaccess functions check proper permissions on group or global areas.

i have 2 tables (user_access, group_access) have similar schema default {{auth_assignment}} table, of not using now. using {{auth_item}}, {{auth_item_child}}, , {{auth_rule}} tables.

i have 2 models, 1 each of access tables groupaccess => group_access, , useraccess => user_access.

i have model access functions , have mapped components configuration.

here access model:

<?php  namespace app\models;  use yii;  class access {  public function canuser($type, $permissionname, $params = []) {      switch ($type) {          case 'group':          $userid = yii::$app->user->identity->id;         $groupid = yii::$app->options->getoption('user', 'active_group_id');          $queryall = groupaccess::find()         ->where('user_id = :user_id , group_id = :group_id', [':user_id' => $userid, ':group_id' => $groupid])         ->asarray()         ->all();          $assignments = [];         foreach ($queryall $queryitem) {             $assignments[$queryitem['item_name']] = [             'userid' => $queryitem['user_id'],             'rolename' => $queryitem['item_name'],             'createdat' => $queryitem['created_date'],             ];         }          $result = self::checkaccess($userid, $permissionname, $assignments, $params);          return $result;          break;          case 'user':          $userid = yii::$app->user->identity->id;          $queryall = useraccess::find()         ->where(['user_id' => $userid])         ->asarray()         ->all();          $assignments = [];         foreach ($queryall $queryitem) {             $assignments[$queryitem['item_name']] = [             'userid' => $queryitem['user_id'],             'rolename' => $queryitem['item_name'],             'createdat' => $queryitem['created_date'],             ];         }          $result = self::checkaccess($userid, $permissionname, $assignments, $params);          return $result;          break;      }  }  public function checkaccess($userid, $permissionname, $assignments, $params = []) {      $auth = yii::$app->authmanager;      $auth->loadfromcache();      if ($auth->items !== null) {         return $auth->checkaccessfromcache($userid, $permissionname, $params, $assignments);     } else {         return $auth->checkaccessrecursive($userid, $permissionname, $params, $assignments);     } }  public function assign($type, $role, $userid = null, $groupid = null) {      switch ($type) {          case 'group':          // clear existing assigments         self::revoke('group', $userid, $groupid);          $groupaccess = new groupaccess();         $groupaccess->group_id = $groupid;         $groupaccess->user_id = $userid;         $groupaccess->item_name = $role;         $groupaccess->created_date = time();          return $groupaccess->save();          break;          case 'user':          // clear existing assignments         self::revoke('user', $userid);          $useraccess = new useraccess();         $useraccess->user_id = $userid;         $useraccess->item_name = $role;         $useraccess->created_date = time();          return $useraccess->save();          break;      }  }  public function revoke($type, $userid, $groupid = null) {      switch ($type) {          case 'group':          groupaccess::deleteall('user_id = :user_id , group_id = :group_id', [':user_id' => $userid, ':group_id' => $groupid]);          break;          case 'user':          useraccess::deleteall('user_id = :user_id', [':user_id' => $userid]);          break;      }  }  } 

and here sample uses access functions:

// user option echo yii::$app->options->getoption('user', 'active_group_id');  // assign group role yii::$app->access->assign('group', 'group_creator', 22, 18); // assign user role yii::$app->access->assign('user', 'app_user', 22);  // revoke group access yii::$app->access->revoke('group', 22, 18); // revoke user access yii::$app->access->revoke('user', 22);  // test user permission var_dump(yii::$app->access->canuser('user', 'manage_app_settings')); // test group permission var_dump(yii::$app->access->canuser('group', 'manage_group_settings')); 

in essence, copied checkaccess function dbmanager , reworked little check user access based on group.

the issue, had make change actual source dbmanager class make $items (property), checkaccessfromcache (function), , checkaccessrecursive (function) public can accessed outside of class. main drawback updateability...

any way around this?

thanks.

here working final solution.

so, day, more refactoring.

my final solution uses checkaccess function in dbmanager/managerinterface source files, added $assignments parameter passed. main issue had build own assignments list checking. make sure comment out lines $assignments variable set.

here new access model:

<?php  namespace app\models;  use yii;  class access {  public function canuser($type, $permissionname, $params = []) {      $auth = yii::$app->authmanager;      switch ($type) {          case 'group':          $userid = yii::$app->user->identity->id;         $groupid = yii::$app->options->getoption('user', 'active_group_id');          $queryall = groupaccess::find()         ->where('user_id = :user_id , group_id = :group_id', [':user_id' => $userid, ':group_id' => $groupid])         ->asarray()         ->all();          $assignments = [];         foreach ($queryall $queryitem) {             $assignments[$queryitem['item_name']] = [             'userid' => $queryitem['user_id'],             'rolename' => $queryitem['item_name'],             'createdat' => $queryitem['created_date'],             ];         }          $result = $auth->checkaccess($userid, $permissionname, $assignments, $params);          return $result;          break;          case 'user':          $userid = yii::$app->user->identity->id;          $queryall = useraccess::find()         ->where('user_id = :user_id', [':user_id' => $userid])         ->asarray()         ->all();          $assignments = [];         foreach ($queryall $queryitem) {             $assignments[$queryitem['item_name']] = [             'userid' => $queryitem['user_id'],             'rolename' => $queryitem['item_name'],             'createdat' => $queryitem['created_date'],             ];         }          $result = $auth->checkaccess($userid, $permissionname, $assignments, $params);          return $result;          break;      }  }  public function assign($type, $role, $userid = null, $groupid = null) {      switch ($type) {          case 'group':          // clear existing assigments         self::revoke('group', $userid, $groupid);          $groupaccess = new groupaccess();         $groupaccess->group_id = $groupid;         $groupaccess->user_id = $userid;         $groupaccess->item_name = $role;         $groupaccess->created_date = time();          return $groupaccess->save();          break;          case 'user':          // clear existing assignments         self::revoke('user', $userid);          $useraccess = new useraccess();         $useraccess->user_id = $userid;         $useraccess->item_name = $role;         $useraccess->created_date = time();          return $useraccess->save();          break;      }  }  public function revoke($type, $userid, $groupid = null) {      switch ($type) {          case 'group':          groupaccess::deleteall('user_id = :user_id , group_id = :group_id', [':user_id' => $userid, ':group_id' => $groupid]);          break;          case 'user':          useraccess::deleteall('user_id = :user_id', [':user_id' => $userid]);          break;      }  }  } 

and here modified checkaccess function in dbmanager:

public function checkaccess($userid, $permissionname, $assignments, $params = []) {     //$assignments = $this->getassignments($userid);     $this->loadfromcache();     if ($this->items !== null) {         return $this->checkaccessfromcache($userid, $permissionname, $params, $assignments);     } else {         return $this->checkaccessrecursive($userid, $permissionname, $params, $assignments);     } } 

and here modified checkaccess function in managerinterface.php:

public function checkaccess($userid, $permissionname, $assignments, $params = []); 

i did not change $items, checkaccessfromcache, , checkaccessrecursive functions public protected.

and here useraccess model:

<?php  namespace app\models;  use yii; use yii\db\activerecord;   /**  * model class table "app_user_access".  *  * @property integer $id  * @property integer $user_id  * @property string $item_name  * @property integer $created_date  *  * @property appauthitem $itemname  * @property appusers $user  */ class useraccess extends activerecord { /**  * @inheritdoc  */ public static function tablename() {     return 'app_user_access'; }  /**  * @inheritdoc  */ public function rules() {     return [         [['user_id', 'item_name', 'created_date'], 'required'],         [['user_id', 'created_date'], 'integer'],         [['item_name'], 'string', 'max' => 64]     ]; }  /**  * @inheritdoc  */ public function attributelabels() {     return [         'id' => 'id',         'user_id' => 'user id',         'item_name' => 'item name',         'created_date' => 'created date',     ]; }  /**  * @return \yii\db\activequery  */ public function getitemname() {     return $this->hasone(appauthitem::classname(), ['name' => 'item_name']); }  /**  * @return \yii\db\activequery  */ public function getuser() {     return $this->hasone(appusers::classname(), ['id' => 'user_id']); } } 

and here the groupaccess model:

<?php  namespace app\models;  use yii; use yii\db\activerecord;   /**  * model class table "app_group_access".  *  * @property integer $id  * @property integer $group_id  * @property integer $user_id  * @property string $item_name  * @property integer $created_date  *  * @property appusers $user  * @property appauthitem $itemname  * @property appgroups $group  */ class groupaccess extends activerecord { /**  * @inheritdoc  */ public static function tablename() {     return 'app_group_access'; }  /**  * @inheritdoc  */ public function rules() {     return [         [['group_id', 'user_id', 'item_name', 'created_date'], 'required'],         [['group_id', 'user_id', 'created_date'], 'integer'],         [['item_name'], 'string', 'max' => 64]     ]; }  /**  * @inheritdoc  */ public function attributelabels() {     return [         'id' => 'id',         'group_id' => 'group id',         'user_id' => 'user id',         'item_name' => 'item name',         'created_date' => 'created date',     ]; }  /**  * @return \yii\db\activequery  */ public function getuser() {     return $this->hasone(appusers::classname(), ['id' => 'user_id']); }  /**  * @return \yii\db\activequery  */ public function getitemname() {     return $this->hasone(appauthitem::classname(), ['name' => 'item_name']); }  /**  * @return \yii\db\activequery  */ public function getgroup() {     return $this->hasone(appgroups::classname(), ['id' => 'group_id']); } } 

and once again, useful samples:

// assign group role yii::$app->access->assign('group', 'group_creator', 24, 20); // assign user role yii::$app->access->assign('user', 'app_user', 24);  // revoke group yii::$app->access->revoke('group', 22, 18); // revoke user yii::$app->access->revoke('user', 22);  // test user permission var_dump(yii::$app->access->canuser('user', 'manage_app_settings')); // test group permission var_dump(yii::$app->access->canuser('group', 'manage_group_settings')); 

Comments

Popular posts from this blog

javascript - AngularJS custom datepicker directive -

javascript - jQuery date picker - Disable dates after the selection from the first date picker -