2008-09-10 5 views
21

J'ai du mal à implémenter ACL dans CakePHP. Après avoir lu la documentation dans le cake manual ainsi que plusieurs autres tutoriels, articles de blog etc, j'ai trouvé l'excellent tutoriel d'Aran Johnson qui a aidé à combler de nombreuses lacunes. Ses exemples semblent entrer en conflit avec d'autres que j'ai vus dans quelques endroits - en particulier dans la structure arborescente ARO qu'il utilise. Dans ses examples, ses groupes d'utilisateurs sont configurés en tant qu'arborescence en cascade, le type d'utilisateur le plus général se trouvant en haut de l'arborescence et ses enfants se connectant pour chaque type d'accès plus restreint. Ailleurs, j'ai généralement vu chaque type d'utilisateur comme un enfant du même type d'utilisateur générique.Configuration de base de données CakePHP ACL: Structure ARO/ACO?

Comment configurer vos ARO et ACO dans CakePHP? Tous les conseils appréciés!

+0

Je suis ici à la recherche de isMine(), que j'ai essayé de définir, mais il semble que cela existe déjà. –

Répondre

49

Le système ACL intégré de CakePHP est très puissant, mais peu documenté en termes de détails d'implémentation réels. Un système que nous avons utilisé avec succès dans un certain nombre de projets basés sur CakePHP est le suivant. Il s'agit d'une modification de certains systèmes d'accès de niveau groupe documented elsewhere. Les objectifs de notre système sont d'avoir un système simple où les utilisateurs sont autorisés au niveau du groupe, mais ils peuvent avoir des droits supplémentaires spécifiques sur les éléments qui ont été créés par eux, ou par utilisateur. Nous voulions éviter de devoir créer une entrée spécifique pour chaque utilisateur (ou plus précisément pour chaque ARO) dans la table aros_acos.

Nous avons une table d'utilisateurs, et une table de rôles.

Utilisateurs

user_id, user_name, role_id

Rôles

id, role_name

Créer l'arbre ARO pour chaque rôle (nous avons généralement 4 rôles - Invité non autorisée (id 1), autorisé Utilisateur (ID 2), Modérateur de 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 à ajouter des alias pour tous ceux-ci, comme l'outil de ligne de commande de gâteau ne le fait pas. Nous utilisons 'Role- {id}' et 'User- {id}' pour tous les nôtres.

Nous créons alors un ROOT BCA -

cake acl create aco/'ROOT'

puis créer ACOs pour tous les contrôleurs sous ce ROOT un:

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

Jusqu'à présent, si normal. Nous ajoutons un champ supplémentaire dans la table aros_acos, appelé _editown, que nous pouvons utiliser comme action supplémentaire dans le composant actionMap du composant ACL.

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 alors configurer le composant Auth d'utiliser la méthode « CRUD », qui valide le contrôleur/action demandée contre le contrôle d'un composant Acl(). 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, cela est assez commandes standard CakePHP. Nous avons une méthode de checkAccess dans le AppController qui ajoute à la substance au niveau du groupe pour vérifier si pour vérifier un groupe ARO ou un utilisateur ARO pour accéder alors:

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

Les méthodes setupAuth() et checkAccess() sont appelés dans le AppController ' s beforeFilter() rappel. Il existe également une méthode isMine dans AppControler (voir ci-dessous) qui vérifie simplement que l'id_utilisateur de l'élément demandé est le même que l'utilisateur actuellement authentifié. Je l'ai laissé pour plus de clarté.

C'est vraiment tout ce qu'il y a à faire. Vous pouvez alors autoriser/refuser l'accès à certains groupes spécifiques 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.

Quoi qu'il en soit, cette façon de la réponse plus que ce que je voulais que ce soit, et il est sans doute à côté de pas de sens, mais j'espère que ce sera une aide pour vous ...

- modifier -

Comme demandé, voici un édité (purement pour la clarté - il y a beaucoup de choses dans notre code standard qui n'a pas de sens ici) isMine() méthode que nous avons dans notre AppController. Je l'ai enlevé beaucoup de choses de la vérification des erreurs aussi, mais c'est l'essence 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; 
} 
+1

:-) merci pour un tel tutoriel. Il m'a sauvé aussi .. :-) –

+0

simple et mieux que la plupart des articles – aWebDeveloper

+0

: @ David me sers CakePHP 2.x et d'essayer d'ajouter quelque chose comme ça aco créer acl gâteau contrôleurs aco utilisateurs puis gâteau acl create index des utilisateurs aco La première commande va me donner une erreur – anasanjaria

Questions connexes