Domanda

Sto lottando per l'attuazione ACL in CakePHP.Dopo la lettura della documentazione in torta manuale così come molti altri tutorial, blog, ecc, ho trovato Aran Johnson ottimo tutorial che ha contribuito a colmare molte delle lacune.I suoi esempi sembrano in conflitto con gli altri che ho visto, però in alcuni punti, specialmente nell'ARO struttura ad albero che egli usa.

Nel suo esempi i suoi gruppi di utenti sono impostati come una cascata albero, con il più generale tipo di utente di essere in cima all'albero, e i suoi figli che si diramano per ogni accesso più limitato tipo.Altrove ho visto solitamente ogni tipo di utente, come un bambino della stessa generica tipo di utente.

Come si fa a impostare il AROs e Oac CakePHP?Qualsiasi e tutti i suggerimenti apprezzato!

È stato utile?

Soluzione

CakePHP built-in sistema di ACL è veramente potente, ma poco documentato in termini di dettagli di implementazione.Un sistema che abbiamo utilizzato con un certo successo in un certo numero di CakePHP progetti è come indicato di seguito.

E ' una modifica di alcuni a livello di gruppo di sistemi di accesso che sono stati documentati altrove.Il nostro sistema è finalizzato a disporre di un sistema semplice in cui gli utenti sono autorizzati, su un gruppo di livello, ma possono avere specifici e ulteriori diritti di elementi che sono stati creati da loro, o su una base per utente.Abbiamo voluto evitare di dover creare una voce specifica per ogni utente (o, più specificamente, per ogni ARO) in aros_acos tabella.

Abbiamo una tabella di Utenti e Ruoli tabella.

Utenti

user_id, user_name, role_id

Ruoli

id, role_name

Creare ARO albero per ogni ruolo (di solito abbiamo 4 ruoli - non autorizzato Ospite (id 1), Utente Autorizzato (id 2), Moderatore del Sito (id 3) e l'Amministratore (id 4)) :

cake acl create aro / Role.1

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

Dopo questo, è necessario utilizzare SQL o phpMyAdmin o simili per aggiungere gli alias per tutti questi, come la torta di strumento a riga di comando non farlo.Usiamo il Ruolo-{id}' e 'User-{id}' per tutti noi.

Abbiamo quindi creare una RADICE ACO -

cake acl create aco / 'ROOT'

e quindi creare ACOs per tutti i controller di sotto di questa RADICE uno:

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

Fin qui tutto normale.Aggiungiamo un ulteriore campo in aros_acos tabella denominata _editown che possiamo utilizzare come ulteriore azione nell'ACL componente actionMap.

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;

Possiamo quindi l'installazione Auth componente di utilizzare il crud' metodo, che convalida la richiesta controller/action contro un AclComponent::check().Nel app_controller abbiamo qualcosa lungo le linee di:

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 ...
    }
}

Di nuovo, questo è abbastanza standard CakePHP roba.Abbiamo poi un metodo checkAccess in AppController che si aggiunge a livello di gruppo, roba per verificare se controllare un gruppo di ARO o un utente ARO per l'accesso:

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('*');
        }
    }
}

Il setupAuth() e checkAccess() i metodi sono chiamati in AppController's beforeFilter() richiamata.C'è un isMine metodo di AppControler troppo (vedi sotto) che controlla che il user_id dell'elemento richiesto è la stessa come l'utente attualmente autenticato.Ho lasciato questo per chiarezza.

Questo è davvero tutto là è ad esso.Quindi è possibile consentire / negare a particolari gruppi di accedere a specifici acos -

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'

Sono sicuro che si ottiene l'immagine.

Comunque, questa risposta è molto più tempo che ho intenzione di essere, e probabilmente rende senza senso, ma spero che sia di qualche aiuto a voi ...

-- edit --

Come richiesto, ecco una cura (solo per chiarezza - c'è un sacco di roba nel nostro codice boilerplate che ha senso qui) isMine() il metodo che abbiamo nel nostro AppController.Ho rimosso un sacco di controllo di errore, anche con le cose, ma questa è l'essenza di esso:

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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top