La mia applicazione ha due aree tecnicamente, un'area globale (feedback, profilo utente, impostazioni utente, ecc.) E un'area di gruppo (contatti, progetti, profilo di gruppo, impostazioni di gruppo, ecc.).Yii2 RBAC assegnazioni multiple per ogni utente in base ai gruppi
Sto usando il DBManager RBAC per l'area globale e funziona perfettamente, ma ho problemi nell'implementare un meccanismo di autorizzazione per l'area del gruppo.
Il motivo è che i gruppi possono essere condivisi tra gli utenti e un utente può avere più assegnazioni nella tabella group_access (id, id_gruppo, id_utente, nome_articolo) poiché potrebbero essere membri di più gruppi e potrebbero avere diversi livelli di autorizzazione per quei gruppi.
Qui è la mia messa a punto di autenticazione:
$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);
Il mio tavolo group_access ha lo stesso schema della tabella auth_assignment, con l'eccezione che ha una colonna group_id, e la colonna user_id non è unica.
L'utente avrà un solo incarico riguardante l'area globale, ma potrebbe avere molti diversi assetti nell'area del gruppo in quanto potrebbero disporre di privilegi di amministratore sul gruppo a, ma solo di privilegi utente sul gruppo b.
mio DB è impostato come:
Utenti (status_id, nome utente, auth_key, password_hash, e-mail, ecc)
Gruppi (status_id, nome, descrizione, ecc)
Group_Access (group_id, user_id, item_name) Ogni utente riceve un compito per ogni gruppo a cui ha accesso.
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' ], ];
La funzione CheckAccess può qualificare l'userID, e posso anche utilizzare la versione più corta "può", che funziona alla grande per l'utente connesso, ma ho bisogno di controllare l'accesso sulla base di una scelta dell'utente come qui di seguito:
Option::getOption('user', 'active_group_id')
Questa è una funzione personalizzata che estrae l'ID di gruppo attivo da una tabella di opzioni utente. Se un utente cambia gruppo, questo verrà modificato. Il mio modello di opzioni ha tre tipi 'app', 'utente', 'gruppo'.
Sarebbe bello se riuscissi a capire una funzione che funziona allo stesso modo del checkAccess nativo, ma che si chiami checkGroupAccess e ottenga automaticamente active_group_id e estrae le assegnazioni utente dalla tabella group_access ed esegua il controllo dei permessi.
Spero che abbia senso.
Grazie per il vostro tempo.
Mike
** AGGIORNATO **
Quindi, ho una soluzione, che utilizza personalizzato funzioni CheckAccess per verificare la presenza di autorizzazioni appropriate per il gruppo o aree globali.
Ho due tabelle (user_access, group_access) che hanno uno schema simile alla tabella {{auth_assignment}} predefinita, di cui non sto utilizzando ora. Sto utilizzando le {{auth_item}}, {{auth_item_child}} e {{auth_rule}} tabelle.
Ho due modelli, uno per ciascuna delle tabelle di accesso GroupAccess => group_access e UserAccess => user_access.
Ho anche un modello per le funzioni di accesso e l'ho mappato alla configurazione dei componenti.
Ecco il mio modello di accesso:
<?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;
}
}
}
e qui sono alcuni di esempio utilizza per accedere alle funzioni:
// 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'));
In sostanza, ho copiato la funzione CheckAccess dal DBManager e rielaborato un poco per verificare l'accesso degli utenti in base al gruppo.
L'unico problema, è che ho dovuto fare una modifica alla classe reale fonte DBManager per rendere gli elementi $ (proprietà), checkAccessFromCache (funzione), e checkAccessRecursive (funzione) tutti i pubblici in modo che possano essere accessibili al di fuori di la classe. Lo svantaggio principale è aggiornabilità ...
Un modo per aggirare questo?
Grazie.
mi hanno inviato una soluzione funzionante. –