Yii2 RBAC-Mehrfachzuweisungen für jeden Benutzer basierend auf Gruppen

Meine Anwendung hat technisch gesehen zwei Bereiche: einen globalen Bereich (Feedback, Benutzerprofil, Benutzereinstellungen usw.) und einen Gruppenbereich (Kontakte, Projekte, Gruppenprofil, Gruppeneinstellungen usw.).

Ich verwende den RBAC DBManager für den globalen Bereich und es funktioniert einwandfrei, aber ich habe Probleme beim Implementieren eines Autorisierungsmechanismus für den Gruppenbereich.

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

Hier ist mein 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 sie eine group_id-Spalte hat und die user_id-Spalte NICHT eindeutig ist.

Der Benutzer hat nur eine Zuweisung für den globalen Bereich, kann jedoch viele verschiedene Zuweisungen für den Gruppenbereich haben, da er möglicherweise Administratorrechte für Gruppe a hat, aber nur Benutzerrechte für Gruppe b.

Meine DB ist wie folgt eingerichtet:

Users (status_id, Benutzername, auth_key, password_hash, E-Mail usw.)

Groups (status_id, name, description, etc)

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, 'item_name' => 'group_creator'],] ;

Die Funktion checkAccess kann die Benutzer-ID qualifizieren, und ich kann sogar die kürzere Version "can" verwenden, die für den angemeldeten Benutzer hervorragend geeignet ist, aber ich muss den Zugriff anhand einer Benutzeroption wie der folgenden überprüfen:

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

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

Es wäre schön, wenn ich eine Funktion finden könnte, die genauso funktioniert wie die native checkAccess-Funktion, aber checkGroupAccess heißt und automatisch die active_group_id abruft und die Benutzerzuweisungen aus der group_access-Tabelle abruft und die Berechtigungsprüfung durchführt.

Ich hoffe das macht Sinn

Vielen Dank für Ihre Zeit

Mik

** AKTUALISIERT *

Also, ich habe eine Lösung, die benutzerdefinierte checkAccess-Funktionen verwendet, um 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 haben wie die Standardtabelle {{auth_assignment}}, von der ich jetzt keine 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 habe es der Komponentenkonfiguration zugeordnet.

Hier ist mein Zugangsmodell:

<?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 für den Zugriff auf die Funktionen:

// 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 habe ich die checkAccess-Funktion aus dem DbManager kopiert und ein wenig überarbeitet, um den Benutzerzugriff basierend auf der Gruppe zu überprüfen.

Das einzige Problem ist, dass ich die eigentliche Quell-DbManager-Klasse ändern musste, um die $ items (Eigenschaft), checkAccessFromCache (Funktion) und checkAccessRecursive (Funktion) öffentlich zu machen, damit auf sie außerhalb der Klasse zugegriffen werden kann. Der Hauptnachteil ist die Aktualisierbarkeit ...

Wie kann ich das umgehen?

Vielen Dank

Antworten auf die Frage(2)

Ihre Antwort auf die Frage