2015-04-01 14 views
7

Meine Anwendung hat technisch zwei Bereiche, einen globalen Bereich (Feedback, Benutzerprofil, Benutzereinstellungen, etc) und einen Gruppenbereich (Kontakte, Projekte, Gruppenprofile, Gruppeneinstellungen, etc).Yii2 RBAC Mehrfachzuweisungen für jeden Benutzer basierend auf Gruppen

Ich verwende den RBAC DBManager für den globalen Bereich, und es funktioniert gut, aber ich habe Probleme bei der Implementierung eines Autorisierungsmechanismus für den Gruppenbereich.

Der Grund dafür ist, dass Gruppen unter den Benutzern geteilt werden können und ein Benutzer möglicherweise mehrere Zuweisungen in der Tabelle group_access (id, group_id, user_id, item_name) hat, da sie Mitglieder mehrerer Gruppen sein können unterschiedliche Berechtigungsstufen für diese Gruppen.

Hier ist meine Auth Setup:

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

Meine group_access Tabelle hat das gleiche Schema wie die auth_assignment Tabelle, mit der Ausnahme, dass es eine group_id Spalte hat, und die user_id Spalte ist nicht eindeutig.

Der Benutzer hat nur eine Zuweisung in Bezug auf den globalen Bereich, kann aber viele verschiedene Aufgaben im Gruppenbereich haben, da er möglicherweise Administratorrechte für Gruppe a, aber nur Benutzerberechtigungen für Gruppe b hat.

Meine DB eingerichtet ist, wie:

  1. Benutzer (status_id, Benutzername, auth_key, password_hash, E-Mail, etc.)

  2. Gruppen (status_id, Name, Beschreibung, etc.)

  3. Group_Access (group_id, user_id, item_name) Jeder Benutzer erhält eine Zuweisung für jede Gruppe, auf die er Zugriff hat.

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

Die checkaccess Funktion der Benutzer-ID qualifizieren können, und ich kann sogar die kürzere „kann“ Version verwenden, die für den angemeldeten Benutzer funktioniert gut, aber ich brauche Zugriff auf einen Benutzer Option wie unten überprüfen basiert:

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

Dies ist eine benutzerdefinierte Funktion, die die aktive Gruppen-ID aus einer Benutzeroptions-Tabelle abruft. Wenn ein Benutzer Gruppen wechselt, wird dies geändert. Mein Optionsmodell hat drei Typen: "App", "Benutzer", "Gruppe".

Es wäre nett, wenn ich eine Funktion herausfinden könnte, die das gleiche wie das native checkAccess ist, aber checkGroupAccess genannt wird und automatisch die active_group_id erhält und die Benutzerzuweisungen aus der Tabelle group_access zieht und die Berechtigungsprüfung durchführt.

Ich hoffe, das macht Sinn.

Vielen Dank für Ihre Zeit.

Mike

** AKTUALISIERT **

Also, ich habe eine Lösung, die benutzerdefinierten Funktionen verwenden checkaccess für die richtigen Berechtigungen für die Gruppe oder globale Bereiche zu überprüfen.

Ich habe zwei Tabellen (user_access, group_access), die ein ähnliches Schema wie die Standard {{auth_assignment}} Tabelle haben, von denen ich jetzt nicht verwende. Ich verwende die Tabellen {{auth_item}}, {{auth_item_child}} und {{auth_rule}}.

Ich habe zwei Modelle, eines für jede der Zugriffstabellen GroupAccess => group_access und UserAccess => user_access.

Ich habe auch ein Modell für die Zugriffsfunktionen und haben es auf die Komponentenkonfiguration zugeordnet.

Hier mein Zugangsmodell ist:

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

    } 

} 

} 

Und hier sind einige Beispiele die Funktionen für den Zugriff verwendet:

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

Im Wesentlichen kopierte ich die checkaccess-Funktion aus dem DbManager und nachbearbeitet es ein wenig, um den Benutzerzugriff anhand der Gruppe zu überprüfen.

Das einzige Problem ist, dass ich eine Änderung an der tatsächlichen DbManager-Source-Klasse vornehmen musste, um die $ items (Eigenschaft), checkAccessFromCache (function) und checkAccessRecursive (function) alle öffentlich zu machen, damit sie außerhalb von zugegriffen werden können die Klasse. Der Hauptnachteil ist die Aktualisierbarkeit ...

Irgendwo herum?

Danke.

+0

ich geschrieben habe eine funktionierende Lösung. –

Antwort

2

Hier ist eine funktionierende endgültige Lösung.

Also, ein weiterer Tag, mehr Refactoring.

Meine letzte Lösung verwendet die checkAccess-Funktion in den DbManager/ManagerInterface-Quelldateien, aber ich habe den Parameter $ Zuweisungen hinzugefügt, um zu übergeben. Das Hauptproblem ist, dass ich meine eigene Zuweisungsliste für die Überprüfung erstellen musste. Stellen Sie sicher, dass Sie die Zeilen auskommentieren, in denen die Variable $ Zuweisungen festgelegt ist.

Hier ist mein neues Zugangsmodell:

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

    } 

} 

} 

Und hier ist die modifizierte Funktion in 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); 
    } 
} 

Und hier ist die modifizierte Funktion in ManagerInterface.php checkaccess:

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

Ich habe die $ -Elemente, checkAccessFromCache und checkAccessRecursiv nicht geändert e funktioniert öffentlich von geschützt.

Und hier ist mein useraccess Modell:

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

Und hier ist das die group Modell:

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

Und wieder einige nützliche Beispiele:

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