Moja aplikacja ma dwa obszary, obszar globalny (informacje zwrotne, profil użytkownika, ustawienia użytkownika itp.) Oraz obszar grupy (kontakty, projekty, profil grupowy, ustawienia grup itp.).Yii2 RBAC Wiele zadań dla każdego użytkownika na podstawie grup
Używam RBAC DBManager dla obszaru globalnego i działa dobrze, ale mam problemy z wdrażaniem mechanizmu autoryzacji dla obszaru grupy.
Powodem jest to, że grupy mogą być współużytkowane przez użytkowników, a użytkownik może mieć wiele przypisań w tabeli group_access (id, id_grupy, id_użytkownika, nazwa_podmiotu), ponieważ mogą być członkami wielu grup i mogą mieć różne poziomy uprawnień dla tych grup.
Oto moja konfiguracja auth:
$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);
Moja tabela group_access ma taki sam schemat jak stół auth_assignment, z tym wyjątkiem, że ma kolumnę group_id, a kolumna user_id nie jest unikalna.
Użytkownik będzie miał tylko jedno przypisanie dotyczące obszaru globalnego, ale może mieć wiele różnych przypisań w obszarze grupy, ponieważ mogą mieć uprawnienia administratora w grupie a, ale tylko prywatne uprawnienia użytkownika w grupie b.
My DB jest skonfigurowany tak:
użytkowników (status_id, podając nazwę użytkownika, auth_key, password_hash, email, etc)
grup (status_id, nazwa, opis, itp)
Group_Access (group_id, user_id, item_name) Każdy użytkownik otrzymuje jedno zadanie dla każdej grupy, do której ma dostęp.
sample_group_access_records [ [ 'id' => 1 'id_użytkownika' => 35 'group_id' => 17 'nazwa_pozycji' => 'group_admin' ] [ 'id' => 2, 'id_użytkownika' => 35 'group_id' => 356 'nazwa_pozycji' => 'group_user' ] [ 'id' => 3 'id_użytkownika' => 35 'group_id' => 211, 'item_name' => 'group_creator' ], ];
Funkcja checkAccess można zakwalifikować identyfikator użytkownika i mogę nawet użyć krótszego „can” wersję, która działa świetnie dla zalogowanego użytkownika, ale muszę sprawdzić dostęp na podstawie opcji określanych przez użytkownika, takich jak poniżej:
Option::getOption('user', 'active_group_id')
Jest to niestandardowa funkcja, która pobiera aktywny identyfikator grupy z tabeli opcji użytkownika. Jeśli użytkownik zmieni grupę, zostanie to zmienione. Mój model opcji ma trzy typy: "aplikacja", "użytkownik", "grupa".
Byłoby miło, gdybym mógł wymyślić funkcję, która działa tak samo jak natywny checkAccess, ale nazywać się checkGroupAccess i automatycznie pobierać wartości active_group_id i wyciągać przypisania użytkowników z tabeli group_access i wykonywać sprawdzanie uprawnień.
Mam nadzieję, że to ma sens.
Dziękuję za poświęcony czas.
Mike
** AKTUALIZACJA **
Tak, mam rozwiązanie, które wykorzystuje niestandardowe funkcje checkAccess aby sprawdzić odpowiednie uprawnienia w grupie lub obszarze globalnych.
Mam dwie tabele (user_access, group_access), które mają podobny schemat do domyślnej tabeli {{auth_assignment}}, której teraz nie używam. Korzystam z tabel {{auth_item}}, {{auth_item_child}} i {{auth_rule}}.
Mam dwa modele, po jednym dla każdej z tabel dostępu GroupAccess => group_access i UserAccess => user_access.
Mam również model funkcji dostępu i zmapowałem go do konfiguracji komponentów.
Oto mój model dostępu:
<?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;
}
}
}
A oto niektóre próbki wykorzystuje się dostęp do funkcji:
// 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'));
w istocie, skopiowałem funkcję checkAccess z DbManager i przerobione to niewiele, aby sprawdzić dostęp użytkownika na podstawie grupy.
Jedynym problemem jest to, że musiałem zmienić rzeczywistą klasę źródłową DbManager tak, aby pozycje $ (właściwość), checkAccessFromCache (funkcja) i checkAccessRecursive (funkcja) były dostępne publicznie, aby można było uzyskać do nich dostęp poza klasa. Główną wadą jest aktualizacja ...
Dookoła tego?
Dzięki.
Pisałem działające rozwiązanie. –