Yii2 RBAC Multiple Assignments for Each User Based on Groups

前端 未结 1 1070
夕颜
夕颜 2021-02-15 12:42

My application technically has two areas, a global area (feedback, user profile, user settings, etc) and a group area (contacts, projects, group profile, group settings, etc).

相关标签:
1条回答
  • 2021-02-15 13:48

    Here is a working final solution.

    So, another day, more refactoring.

    My final solution uses the checkAccess function in the DbManager/ManagerInterface source files, but I added the $assignments parameter to be passed. The main issue is that I had to build my own assignments list for checking. Make sure you comment out the lines where the $assignments variable is set.

    Here is my 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 and group_id = :group_id', [':user_id' => $userID, ':group_id' => $groupID])
            ->asArray()
            ->all();
    
            $assignments = [];
            foreach ($queryAll as $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 as $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 and 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 is the 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 is the modified checkAccess function in ManagerInterface.php:

    public function checkAccess($userId, $permissionName, $assignments, $params = []);
    

    I did not change the $items, checkAccessFromCache, and checkAccessRecursive functions to public from protected.

    And here is my UserAccess model:

    <?php
    
    namespace app\models;
    
    use Yii;
    use yii\db\ActiveRecord;
    
     /**
     * This is the model class for 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 is the the GroupAccess Model:

    <?php
    
    namespace app\models;
    
    use Yii;
    use yii\db\ActiveRecord;
    
     /**
     * This is the model class for 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, some 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 the group permission
    var_dump(Yii::$app->access->canUser('group', 'manage_group_settings'));
    
    0 讨论(0)
提交回复
热议问题