Мое приложение технически имеет две области: глобальную область (обратная связь, профиль пользователя, пользовательские настройки и т. Д.) И область группы (контакты, проекты, групповой профиль, групповые настройки и т. Д.).).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 может претендовать на идентификатор_пользователь, и я могу даже использовать более короткую «можно» версию, которая прекрасно работает для зарегистрированного пользователя, но мне нужно, чтобы проверить доступ на основании пользовательского параметра, как показано ниже:
Option::getOption('user', 'active_group_id')
Это настраиваемая функция, которая вытаскивает активный идентификатор группы из таблицы параметров пользователя. Если пользователь переключает группы, это будет изменено. Моя модель имеет три типа «приложение», «пользователь», «группа».
Было бы неплохо, если бы я мог найти функцию, которая работает так же, как и 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'));
В сущности, я скопировал функцию CheckAccess из DBManager и переработан его мало для проверки доступа пользователей на основе группы.
Единственная проблема заключается в том, что мне пришлось внести изменения в фактический исходный класс DbManager, чтобы сделать все объекты (свойства), checkAccessFromCache (function) и checkAccessRecursive (function) общедоступными, чтобы к ним можно было получить доступ за пределами класс. Основным недостатком является возможность обновления ...
В любом случае?
Спасибо.
Я отправил рабочее решение. –