我的應用程序在技術上有兩個區域,全局區域(反饋,用戶配置文件,用戶設置等)和組區域(聯繫人,項目,組配置文件,組設置等)。Yii2 RBAC基於組的每個用戶的多個分配
我在全局區域使用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有用戶權限。
我的DB設置如下:
用戶(STATUS_ID,用戶名,AUTH_KEY,password_hash,電子郵件等)
組(STATUS_ID,名稱,說明等)
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,而我甚至可以用更短的「可以」版本,它的偉大工程的登錄用戶,但我需要基於類似下面的用戶選項檢查訪問:
Option::getOption('user', 'active_group_id')
這是一個自定義函數,用於從用戶選項表中提取活動組標識。如果用戶切換組,這將會改變。我的選項模型有三種類型'應用','用戶','組'。
如果我能找出一個與本地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(property),checkAccessFromCache(function)和checkAccessRecursive(function)全部公開,以便它們可以在班上。主要缺點是可更新性...
任何方法?
謝謝。
我已經發佈一個工作解決方案 – 2015-04-05 01:56:51