Recoder les ACL de cakephp
Pour un projet perso, j’ai du mettre un système de droit (admin, membre ) en place sur un site cakephp. Je devais le faire dans la matinée donc je me suis donc mis à lire la doc’ sur les ACL.
Honnêtement, je n’ai rien compris à ces histoires de nain qui boivent de la bière 😀 (et puis l’environnement bruyant autour de moi ne m’a pas aidé).
J’ai donc tenté de recoder mes ACL selon mes besoins et devinez quoi, ça m’a pris une heure (plus rapidement que le temps que j’ai accordé à la lecture de la doc’ sur les ACL 😀 ).
Allez hop on est parti.
Quasiment tout le traitement va se passer dans votre AppController et il faudra paramétrer vos propres routes. Vous avez donc uniquement 2 fichiers à modifier.
Coté structure, il vous faut seulement un champ « admin » dans votre table users.
Pour la première partie du tuto, nous dirons que si on est un simple membre, le champ est à 0 et à 1 si on est admin pour le champ « admin ».
Utiliser les préfixes en cakephp
Je pars du principe que vous avez suivi le tutoriel de la doc’ pour créer un espace membre et que vous avez la table users avec un champ « admin ».
Pour accomplir notre but, nous allons utiliser les préfixes. Pas de panique si vous ne savez pas ce que c’est.
Créez un fichier TestController.php donc votre dossier app/Controller:
class TestController extends AppController { public function membre_index() { var_dump($this->params['prefix']); } }
Vous devriez avoir
string 'membre' (length=6)
Si vous allez sur cette URL : /membre/test
Et que vous activez les préfixes à la ligne 152 du fichier app/Config/core.php
Configure::write('Routing.prefixes', array('admin','membre'));
Nous allons maintenant réécrire les urls pour les avoir plus sympas.
Alors attention, cette règle est puissante puisqu’elle réécrit TOUTES les urls qui ont un controller et une action. Personnellement, je trouve plus sympa d’avoir /controller/view que /membre/controller/view.
Modifiez votre fichier app/Config/routes.php et ajoutez cette ligne :
Router::connect("/:controller/:action/*", array('prefix' => 'membre', 'membre' => true));
Recoder les ACL
Dans votre appController, modifiez votre beforeFilter() comme ceci:
public function beforeFilter() { $this->Auth->allow(); $current_user=$this->Auth->user('id'); if($this->params['prefix']=="membre") { if($current_user == NULL) { $this->Session->setFlash("Cette action necessite d'etre connecté.", "notice",array('type'=>'info')); $this->redirect('/connexion'); } } }
Alors qu’est-ce qu’on a fait?
On vérifie si l’action contient un préfixe et qu’il est égal à « membre ». Ensuite, on récupère la session du membre, si elle est égale à NULL c’est que le membre n’est pas loggué.
On envoie une notice pour indiquer l’erreur et on redirige sur la page de connexion.
Pour tester, il suffit de ne pas être connecté, de créer une action « membre_supp » dans votre testcontroller et d’essayer d’accéder à l’url /test/supp
Nous allons maintenant faire la vérification pour le niveau admin.
Comme pour les membres, il vous faut faire 2 modifications, le fichier routes et l’appcontroller.
Pour le fichier routes:
Router::connect("/admin/:controller/:action/*", array('prefix' => 'admin', 'admin' => true));
Mettez cette route AVANT celle des membres (vu que la route membre réécrit toutes les URLS).
Comme vous avez pu le comprendre, nos URLS admin, ressembleront à admin/controller/action.
Pour le fichier appcontroller dans l’action beforeFilter, vous ajoutez:
if($this->params['prefix']=="admin") { if($this->Auth->user("admin")==="0") { $this->Session->setFlash("Cette action necessite d'etre admin. oh l'autre et ...", "notice",array('type'=>'info')); $this->redirect('/users'); } elseif($this->Auth->user('admin')==NULL) { $this->Session->setFlash("Cette action necessite d'etre connecté.", "notice",array('type'=>'info')); $this->redirect('/connexion'); } }
Qu’est-ce qu’on a fait?
On vérifie si le préfixe est admin, si oui, on vérifie si le champ en base du membre est 0 (donc simple membre). Si c’est un simple membre, on indique un message d’erreur et on redirige sur son compte sinon s’il n’est pas connecté, on redirige sur la page de connexion.
Vous avez normalement un système de droit fonctionnel, on aurait pu s’arrêter là mais vous me connaissez, on va optimiser tout ça 😀
Bon là, vous allez vous me dire, c’est cool ce système mais si on veut rajouter encore un niveau (modérateur, par exemple), on va devoir encore rajouter un if et refaire toutes les vérifications.
Ok, ok, réduisons ça.
Nous allons faire 2 tableaux, un pour la correspondance entre le champ en base et la valeur du préfixe et un autre pour indiquer tous nos prefixes.
On va partir du principe que le rôle :
- admin a la valeur 1
- modérateur a la valeur 0
- membre a la valeur -1
Du coup, on va remplacer notre beforeFilter avec ce code :
$array_niveau=array('admin'=>1, 'modo'=> 0, 'membre'=>-1); $array_prefix=array('admin', 'modo', 'membre'); $prefix=$this->params['prefix']; if(in_array($prefix, $array_prefix)) { if($this->Auth->user('admin')==NULL) { $this->Session->setFlash("Cette action necessite d'etre connecté.", "notice",array('type'=>'info')); $this->redirect('/connexion'); } if($array_niveau[$prefix] > $this->Auth->user('admin')) { $this->Session->setFlash("Cette action necessite un plus haut niveau d'accreditation.", "notice",array('type'=>'info')); $this->redirect('/connexion'); } }
Qu’est-ce qu’on a fait?
On vérifie si notre préfixe est bien dans notre tableau $array_prefix.
Si le membre n’est pas connecté, on redirige sur la page connexion avec un message.
Sinon on vérifie si le chiffre d’équivalence du rôle est supérieur à celui du membre connecté. Comme vous l’avez vu, plus le niveau est haut, plus le chiffre est haut. Donc si le membre a un rôle « admin » inférieur au tableau $array_niveau, on le redirige avec un message d’erreur.
Bonus : rediriger sur l’admin
Alors si vous allez sur l’url /admin directement, vous devez avoir un message d’erreur comme quoi le controlleur « admin » n’existe pas (ce qui est normal). Donc je vous propose le code qui va suivre pour rediriger sur la gestion des membres automatiquement.
Code à mettre dans votre beforeFilter :
if($this->params['controller']=="admin") { $prefix="admin"; $controller=explode('_', $this->params['action']); if($controller[0]=="index") $controller="users"; else $controller=$controller[1]; $action="index"; $this->redirect('/'.$prefix.'/'.$controller.'/'.$action); }
Ce qu’il ne faut pas oublier
Il ne faut pas oublier de toujours donner comme préfixe à votre action, le rang minimum. Si votre action est accessible aux modérateurs et aux admins, il faudra lui donner un préfixe « modo ».
Pensez à ajouter vos routes pour chaque rôle ajouté et méfiez-vous de la route membre qui réécrit toutes les urls.
Celle règle est tellement puissante qu’elle bloque aussi vos 404, si le membre tape en url /machin/truc, il sera redirigé vers la page connexion. Si ce comportement ne vous va pas, modifiez-la, comme la règle admin par exemple.
Vous devez créer une route pour chaque action sans préfixe si vous gardez la route membre telle qu’elle. Si votre site demande une authentification sur quasiment toutes vos pages, vous n’aurez besoin de routes que pour la page de connexion et d’inscription. Si votre site a nombre important d’action « publiques », c’est un choix que vous devrez faire.
Vous savez désormais utiliser les préfixes cakephp, créer vos propres routes et coder vos propres ACL, au besoin.
Si vous avez apprécié cet article, n’hésitez pas à le partager sur les réseaux sociaux et/ou de laisser un commentaire ci dessous.
Bon dev à vous 😉