gpt4 book ai didi

mysql - 基于组的每个用户的 Yii2 RBAC 多重分配

转载 作者:可可西里 更新时间:2023-11-01 06:38:18 25 4
gpt4 key购买 nike

我的应用程序在技术上有两个区域,一个全局区域(反馈、用户配置文件、用户设置等)和一个组区域(联系人、项目、组配置文件、组设置等)。

我正在为全局区域使用 RBAC DBManager,它工作得很好,但我在为组区域实现授权机制时遇到了问题。

原因是组可以在用户之间共享,并且用户可能在 group_access 表中有多个分配(id、group_id、user_id、item_name),因为他们可能是多个组的成员,并且他们可能有不同的这些组的权限级别。

这是我的身份验证设置:

$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);

我的 group_access 表与 auth_assignment 表具有相同的架构,除了它有一个 group_id 列,并且 user_id 列不是唯一的。

用户将只有一个关于全局区域的分配,但在组区域上可能有许多不同的分配,因为他们可能在组 a 上具有管理员权限,但在组 b 上只有用户权限。

我的数据库设置如下:

  1. 用户(status_id、用户名、auth_key、password_hash、电子邮件等)

  2. 群组(status_id、名称、描述等)

  3. Group_Access (group_id, user_id, item_name) 每个用户都会为他们有权访问的每个组分配一个任务。

    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' ],];

checkAccess 函数可以限定用户 ID,我什至可以使用更短的“can”版本,这对登录用户非常有用,但我需要根据用户选项检查访问权限,如下所示:

Option::getOption('user', 'active_group_id')

这是一个自定义函数,可从用户选项表中提取事件组 ID。如果用户切换组,这将被更改。我的选项模型具有三种类型“app”、“user”、“group”。

如果我能找出一个与 native checkAccess 工作方式相同但被称为 checkGroupAccess 并自动获取 active_group_id 并从 group_access 表中提取用户分配并执行权限检查的函数,那就太好了。

我希望这是有道理的。

感谢您的宝贵时间。

迈克

** 已更新 **

所以,我有一个解决方案,它使用自定义 checkAccess 函数来检查组或全局区域的适当权限。

我有两个表(user_access、group_access),它们具有与默认 {{auth_assignment}} 表相似的架构,我现在没有使用它们。我正在使用 {{auth_item}}、{{auth_item_child}} 和 {{auth_rule}} 表。

我有两个模型,一个用于访问表 GroupAccess => group_access 和 UserAccess => user_access。

我还有一个访问函数模型,并将其映射到组件配置。

这是我的访问模型:

<?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 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 = 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 as $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 and group_id = :group_id', [':user_id' => $userID, ':group_id' => $groupID]);

break;

case 'user':

UserAccess::deleteAll('user_id = :user_id', [':user_id' => $userID]);

break;

}

}

}

下面是一些访问函数的示例:

// get the 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 the group permission
var_dump(Yii::$app->access->canUser('group', 'manage_group_settings'));

本质上,我从 DbManager 复制了 checkAccess 函数并对其进行了一些修改,以检查基于组的用户访问权限。

唯一的问题是,我必须更改实际的源 DbManager 类,使 $items(属性)、checkAccessFromCache(函数)和 checkAccessRecursive(函数)全部公开,以便可以在外部访问它们类(class)。主要缺点是可更新性...

有什么办法解决这个问题吗?

谢谢。

最佳答案

这是一个可行的最终解决方案。

所以,改天,更多的重构。

我的最终解决方案使用 DbManager/ManagerInterface 源文件中的 checkAccess 函数,但我添加了要传递的 $assignments 参数。主要问题是我必须建立自己的作业 list 以供检查。确保注释掉设置 $assignments 变量的行。

这是我的新访问模型:

<?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;

}

}

}

这里是 DbManager 中修改后的 checkAccess 函数:

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);
}
}

这里是 ManagerInterface.php 中修改后的 checkAccess 函数:

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

我没有将 $items、checkAccessFromCache 和 checkAccessRecursive 函数从 protected 更改为 public。

这是我的 UserAccess 模型:

<?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']);
}
}

这是 GroupAccess 模型:

<?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']);
}
}

再一次,一些有用的示例:

// 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'));

关于mysql - 基于组的每个用户的 Yii2 RBAC 多重分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29381801/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com