Question

J'ai du mal à mettre en œuvre des ACL dans CakePHP.Après la lecture de la documentation dans le gâteau manuel ainsi que plusieurs autres tutoriels, des articles de blog, etc, j'ai trouvé Aran Johnson excellent tutoriel qui a permis de combler de nombreuses lacunes.Ses exemples semblent entrer en conflit avec d'autres que j'ai vu si dans quelques endroits, en particulier dans le ARO structure de l'arbre qu'il utilise.

Dans son exemples ses groupes d'utilisateurs sont mis en place comme une cascade d'arbre, avec la plus générale, le type d'utilisateur en cours au sommet de l'arbre, et ses enfants de bifurquer pour chaque plus restreinte type d'accès.D'ailleurs j'ai souvent vu chaque type d'utilisateur en tant qu'enfant de la même générique du type d'utilisateur.

Comment définissez-vous votre mise hors service d'immobilisations et des ACOs dans CakePHP?Tout et tous les conseils sont appréciés!

Était-ce utile?

La solution

CakePHP est intégré dans le système d'ACL est vraiment puissant, mais peu documentées en termes de mise en œuvre effective de détails.Un système que nous avons utilisé avec un certain succès dans un certain nombre de CakePHP projets est comme suit.

C'est une modification au niveau du groupe systèmes d'accès qui ont été documenté ailleurs.Notre système a pour but d'avoir un système simple où les utilisateurs sont autorisés, dans un groupe de niveau, mais elles peuvent être spécifiques à des droits supplémentaires sur les articles qui ont été créés par eux, ou sur une base par utilisateur.Nous voulions éviter d'avoir à créer une entrée spécifique pour chaque utilisateur (ou, plus précisément, pour chaque ARO) dans le aros_acos table.

Nous avons une table des Utilisateurs, et un tableau des Rôles.

Les utilisateurs

user_id, user_name, role_id

Les rôles

id, role_name

Créer l'arbre d'ARO pour chaque rôle (nous avons habituellement des 4 rôles non autorisée d'Hôtes (id 1), l'Utilisateur Autorisé (id 2), Modérateur du Site (id 3) et Administrateur (id 4)) :

cake acl create aro / Role.1

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

Après cela, vous devez utiliser SQL ou phpMyAdmin ou similaire pour ajouter des alias dans tous ces cas, comme le gâteau outil de ligne de commande ne pas le faire.Nous utilisons le Rôle-{id} " et " Utilisateur{id}' pour l'ensemble de la nôtre.

Nous créons ensuite une RACINE ACO -

cake acl create aco / 'ROOT'

et puis créer ACOs pour tous les contrôleurs en vertu de cette RACINE:

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

C'est très normal.Nous avons ajouter un champ supplémentaire dans la aros_acos table appelée _editown que l'on peut utiliser comme une action supplémentaire dans le composant ACL de 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;

On peut ensuite configurer le composant Auth à utiliser le "crud " méthode", qui valide la demande de contrôleur/action à l'encontre d'un composant acl::check().Dans le app_controller nous avons quelque chose le long des lignes de:

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

Encore une fois, c'est assez standard CakePHP choses.Nous avons ensuite une méthode checkAccess dans AppController qui ajoute dans le groupe de niveau stuff pour vérifier si la vérification d'un groupe de ARO ou un utilisateur ARO pour l'accès:

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

L' setupAuth() et checkAccess() les méthodes sont appelées dans l' AppController's beforeFilter() de rappel.Il y a un isMine méthode dans le AppControler trop (voir ci-dessous) qui vérifie juste que le user_id de l'élément demandé est le même que l'utilisateur actuellement authentifié.J'ai quitté ce pour plus de clarté.

C'est vraiment tout là est à lui.Vous pouvez alors autoriser / refuser certains groupes l'accès à certaines 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'

Je suis sûr que vous obtenez l'image.

De toute façon, cette réponse est plus long que j'ai prévu, et probablement il fait à peu près aucun sens, mais j'espère que c'est un peu d'aide pour vous ...

-- edit --

Comme demandé, voici un montage (purement pour des raisons de clarté - il y a beaucoup de choses dans notre code réutilisable qui est vide de sens ici) isMine() la méthode que nous avons dans notre AppController.J'ai enlevé beaucoup de vérification des erreurs des trucs aussi, mais c'est l'essence même de celui-ci:

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top