Frage

Ich habe Schwierigkeiten, ACL in CakePHP zu implementieren.Nach dem Lesen der Dokumentation in der Kuchenhandbuch Neben mehreren anderen Tutorials, Blog-Beiträgen usw. habe ich das hervorragende Tutorial von Aran Johnson gefunden, das dazu beigetragen hat, viele Lücken zu schließen.Seine Beispiele scheinen jedoch an einigen Stellen im Widerspruch zu anderen zu stehen, die ich gesehen habe – insbesondere in der von ihm verwendeten ARO-Baumstruktur.

In seinem Beispiele Seine Benutzergruppen sind als kaskadierender Baum aufgebaut, wobei sich der allgemeinste Benutzertyp an der Spitze des Baums befindet und seine untergeordneten Benutzer für jeden Typ mit eingeschränkterem Zugriff verzweigen.An anderer Stelle habe ich normalerweise jeden Benutzertyp als Kind desselben generischen Benutzertyps gesehen.

Wie richten Sie Ihre AROs und ACOs in CakePHP ein?Jeder Tipp ist willkommen!

War es hilfreich?

Lösung

CakePHP-internes ACL-System ist wirklich mächtig, aber schlecht im Hinblick auf den tatsächlichen Umsetzung Details dokumentiert. Ein System, das wir mit einigem Erfolg in einer Reihe von CakePHP-basierten Projekten verwendet haben, ist wie folgt.

Es ist eine Modifikation einiger Gruppenebene Zugangssysteme, die gewesen sind anderswo dokumentiert. Unser System die Ziele sind ein einfaches System haben, wo Benutzer auf eine Gruppe-Ebene zugelassen werden, aber sie können bestimmte zusätzliche Rechte auf Elemente, die von ihnen oder auf einer Pro-Benutzer-Basis erstellt wurden. Wir wollten vermeiden, für jeden Benutzer einen bestimmten Eintrag zu erstellen (oder, genauer gesagt für jede ARO) in der aros_acos Tabelle.

Wir haben eine Benutzertabelle und eine Tabelle Rollen.

Nutzer

user_id, user_name, role_id

Rollen

id, role_name

für jede Rolle den ARO Baum erstellen (wir haben in der Regel vier Rollen - Nicht autorisierten Guest (id 1) Berechtigter Benutzer (id 2), Site-Moderator (id 3) und Administrator (id 4)):

cake acl create aro / Role.1

cake acl create aro 1 Role.2 ... etc ...

Danach müssen Sie SQL oder phpMyAdmin oder ähnliches verwenden, Aliase für alle diese hinzuzufügen, wie der Kuchen Kommandozeilen-Tool ist es nicht zu tun. Wir verwenden 'Rollen- {id}' und 'User- {id}' für alle von uns.

Wir erstellen dann eine ROOT ACO -

cake acl create aco / 'ROOT'

und erstellen ACOs für alle Steuerungen im Rahmen dieser ROOT ein:

cake acl create aco 'ROOT' 'MyController' ... etc ...

So weit, so normal. Wir fügen ein zusätzliches Feld in der aros_acos Tabelle namens _editown, die wir als zusätzliche Maßnahme in der ACL Komponente actionMap verwenden können.

CREATE TABLE IF NOT EXISTS `aros_acos` (
`id` int(11) NOT NULL auto_increment,
`aro_id` int(11) default NULL,
`aco_id` int(11) default NULL,
`_create` int(11) NOT NULL default '0',
`_read` int(11) NOT NULL default '0',
`_update` int(11) NOT NULL default '0',
`_delete` int(11) NOT NULL default '0',
`_editown` int(11) NOT NULL default '0',
PRIMARY KEY  (`id`),
KEY `acl` (`aro_id`,`aco_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

Wir können Setup dann die Auth Komponente, die die ‚crud‘ Methode zu verwenden, die die gewünschten Controller / Aktion gegen eine AclComponent :: check bestätigt (). Im app_controller haben wir etwas entlang der Linien von:

private function setupAuth() {
    if(isset($this->Auth)) {
        ....
        $this->Auth->authorize = 'crud';
        $this->Auth->actionMap = array( 'index'     => 'read',
                        'add'       => 'create',
                        'edit'      => 'update'
                        'editMine'  => 'editown',
                        'view'      => 'read'
                        ... etc ...
                        );
        ... etc ...
    }
}

Auch dies ist ziemlich Standard CakePHP Zeug. Wir haben dann eine Methode checkaccess in den AppController, die in der Gruppe-Ebene Slideshows erstellt zu prüfen, ob eine Gruppe ARO oder einen Benutzer ARO für den Zugang zu überprüfen:

private function checkAccess() {
    if(!$user = $this->Auth->user()) {
        $role_alias = 'Role-1';
        $user_alias = null;
    } else {
        $role_alias = 'Role-' . $user['User']['role_id'];
        $user_alias = 'User-' . $user['User']['id'];
    }

    // do we have an aro for this user?
    if($user_alias && ($user_aro = $this->User->Aro->findByAlias($user_alias))) {
        $aro_alias = $user_alias;
    } else {
        $aro_alias = $role_alias;
    }

    if ('editown' == $this->Auth->actionMap[$this->action]) {
        if($this->Acl->check($aro_alias, $this->name, 'editown') and $this->isMine()) {
            $this->Auth->allow();
        } else {
            $this->Auth->authorize = 'controller';
            $this->Auth->deny('*');
        }
    } else {
        // check this user-level aro for access
        if($this->Acl->check($aro_alias, $this->name, $this->Auth->actionMap[$this->action])) {
            $this->Auth->allow();
        } else {
            $this->Auth->authorize = 'controller';
            $this->Auth->deny('*');
        }
    }
}

Die setupAuth() und checkAccess() Methoden sind in der AppController der beforeFilter() Rückruf aufgerufen. Es gibt eine isMine Methode in dem AppControler zu (siehe unten), die gerade überprüft, ob der user_id des angeforderten Artikels ist das gleiche wie die derzeit authentifizierten Benutzer. Ich habe dies aus Gründen der Übersichtlichkeit weggelassen.

Das ist wirklich alles, was es ist. Anschließend können Sie erlauben / verweigern bestimmte Gruppen auf bestimmte acos Zugriff -

cake acl grant 'Role-2' 'MyController' 'read'

cake acl grant 'Role-2' 'MyController' 'editown'

cake acl deny 'Role-2' 'MyController' 'update'

cake acl deny 'Role-2' 'MyController' 'delete'

Ich bin sicher, Sie erhalten das Bild.

Wie auch immer, diese Antwort Weg länger als wollte ich es sein, und es macht wohl keinen Sinn nächstes, aber ich hoffe, dass es Ihnen etwas Hilfe ist ...

- bearbeiten -

Wie gewünscht, hier ist eine bearbeitete (rein aus Gründen der Klarheit - es gibt eine Menge Sachen in unserem Standardcode, der sinnlos hier) isMine() Methode, die wir in unserem AppController haben. Ich habe zu viele Fehlerprüfung Sachen entfernt, aber das ist die Essenz davon:

function isMine($model=null, $id=null, $usermodel='User', $foreignkey='user_id') {
    if(empty($model)) {
        // default model is first item in $this->uses array
        $model = $this->uses[0];
    }

    if(empty($id)) {
        if(!empty($this->passedArgs['id'])) {
        $id = $this->passedArgs['id'];
        } elseif(!empty($this->passedArgs[0])) {
            $id = $this->passedArgs[0];
        }
    }

    if(is_array($id)) {
        foreach($id as $i) {
            if(!$this->_isMine($model, $i, $usermodel, $foreignkey)) {
                return false;
            }
        }

        return true;
    }

    return $this->_isMine($model, $id, $usermodel, $foreignkey);
}


function _isMine($model, $id, $usermodel='User', $foreignkey='user_id') {
    $user = Configure::read('curr.loggedinuser'); // this is set in the UsersController on successful login

    if(isset($this->$model)) {
        $model = $this->$model;
    } else {
        $model = ClassRegistry::init($model);
    }

    //read model
    if(!($record = $model->read(null, $id))) {
        return false;
    }

    //get foreign key
    if($usermodel == $model->alias) {
        if($record[$model->alias][$model->primaryKey] == $user['User']['id']) {
            return true;
        }
    } elseif($record[$model->alias][$foreignkey] == $user['User']['id']) {
        return true;
    }

    return false;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top