Utilisation de sfDoctrineGuardPlugin pour la gestion des utilisateurs

sfDoctrineGuardPlugin comme son nom l’indique est la version Doctrine de sfGuardPlugin qui est THE plugin de gestion des utilisateurs de Symfony.

Il comporte des formulaires d’identification et d’inscription très basique, mais son principal point fort est la gestion des droits associés aux utilisateurs, la possibilité de gérer des groupes le tout générant automatiquement les crédentials qui va permettre de sécuriser l’application de manière très simple.

Je ne reviendrai pas sur la gestion des crédentials qui est très bien expliquée dans le Jobeet #13.

De même pour l’installation. Le readme est très bien fait et explique très clairement comment faire.

Le modèle de données

Le modèle de données du plugin comporte la table des Utilisateurs, des Groupes et des Permissions ainsi que les tables d’associations entre Utilisateurs/Permissions, Groupes/Permissions et Utilsateurs/Groupes.

Ce sont les permissions attribuées à un utilisateur (directement ou par ses groupes) qui déterminent les crédentials qu’il aura une fois logué (C’est le nom de la permission qui sera le nom du crédential).

Pour illustrer tout ca, on va voir un petit exemple.

On prends une structure simple, avec 2 groupes et 3 permissions.
Les permissions de Lecture, Ecriture et Téléchargement (même si la loi Hadopie a été votée ^^).
Les groupes Admin qui a tous les droits et Membre qui n’a que le droit de lecture.

 
sfGuardPermission:
  pLecture:
    name: lecture
  pEcriture:
    name: ecriture
  pTelegargement:
    name: telechargement
 
sfGuardGroup:
  gAdmin:
    name: admin
  gMembre:
    name: membre
 
sfGuardGroupPermission:
  gp1:
    sfGuardGroup:      gAdmin
    sfGuardPermission: pLecture
  gp2:
    sfGuardGroup:      gAdmin
    sfGuardPermission: pEcriture
  gp3:
    sfGuardGroup:      gAdmin
    sfGuardPermission: pTelegargement
  gp4:
    sfGuardGroup:      gMembre
    sfGuardPermission: pLecture

Et 3 utilisateurs : Toto, Titi et Tata à qui on va définir des droits différents.

– Toto sera dans le groupe admin, il aura ainsi tout les droits.
– Titi et Tata seront dans le groupe Membre et auront ainsi seulement le droit de Lecture.
– Titi a en plus le droit de téléchargement.

Ce qui se traduit en fixture comme ceci :

 
sfGuardUser:
  Toto:
    username: toto
    password: t0t0
  Titi:
    username: titi
    password: t1t1
  Tata:
    username: tata
    password: t4t4
 
sfGuardUserGroup:
  ug1:
    sfGuardUser:  Toto
    sfGuardGroup: gAdmin
  ug2:
    sfGuardUser:  Titi
    sfGuardGroup: gMembre
  ug3:
    sfGuardUser:  Tata
    sfGuardGroup: gMembre
 
sfGuardUserPermission:
  up1:
    sfGuardUser:       Titi
    sfGuardPermission: pTelegargement

Dans un module lambda, on peut donc très facilement sécuriser nos pages comme suit.

/module/config/security.yml

secure:
  is_secure:   on
 
telechargement:
  is_secure:   on
  credentials: [lecture, telechargement]
 
default:
  is_secure:   off

La page secure nécessite que l’utilisateur soit connecté mais il n’y a aucune restriction de crédential. Les 3 utilisateur, une fois logés, pourront y accéder.

La page téléchargement nécessite 2 permissions lecture et téléchargement. Seuls Toto et Titi y auront accès. Tata sera redirigé automatiquement vers la page d’erreur de permissions.

La redirection après l’authentification.

L’authentification est gérée par le plugin, il suffit d’envoyer l’utilisateur vers la route @sf_guard_signin.

Une fois l’authentification effectuée, le script redirige l’utilisateur. Par défaut l’utilisateur est redirigé vers le HTTP_REFERER.

Heureusement on peut aussi déterminer une route vers laquelle on veut être redirigé après l’authentification de plusieurs manières.

Premièrement via des variable du app.yml

all:
  sf_guard_plugin:
    success_signin_url:      @my_route?param=value
    success_signout_url:     module/action

Autre méthode qui consiste à utiliser le comportement par défaut de redirection vers le referer, mais en utilisant la méthode setReferer() de la classe sfGuardSecurityUser.

<?php
class moduleActions extends sfActions
{
  ...
  public function executeAction(sfWebRequest $request)
  {
    ...
    $this->getUser()->setReferer('@my_route');
    $this->redirect('@sf_guard_signin');
  }
}

L’ordre de priorité est :
– la variable du fichier app.yml
– le getReferer() du GuardUser
– le HTTP_REFERER

Connecter automatiquement un utilisateur

Il est possible de connecter automatiquement un utilisateur grâce à la méthode signin() à la quelle on doit passer une instance de sfGuardUser.

Par exemple dans une action quelconque :

<?php
class moduleActions extends sfActions
{
  ...
  public function executeAction(sfWebRequest $request)
  {
    ...
    $utilisateur = Doctrine::getTable('sfGuardUser')->findOneByUsername('toto');
    $this->getUser()->signin($utilisateur);
    ...
  }
}

Associer un ou plusieurs groupes à un utilisateur

On a vu au début de l’article comment associer des groupes aux utilisateurs par le fixture.

On va voir ici comment le faire en php.

Par exemple si on avait à le faire dans le script d’inscription et qu’on veulait associer automatiquement le groupe membre aux utilisateurs qui s’inscrivent.

 
public function executeInscription(sfWebRequest $request)
{
  $this->form = new sfGuardUserFormRegister();
  // la classe de formulaire sfGuardUserFormRegister n'existe pas dans le plugin par defaut
  // je la mets en annexe à la fin de l'article
 
  if($request->isMethod('post'))
  {
    $this->form->bind($request->getParameter($this->form->getName()));
 
    if($this->form->isValid())
    {
      $permission = Doctrine::getTable('sfGuardGroup')->findOneByName('membre');
 
      $utilisateur = $this->form->getObject();
      $utilisateur['permissions'][] = $permission;
      $utilisateur->save();
 
      $this->getUser()->signIn($utilisateur);
      $this->redirect('@homepage');
    }
  }
}

Annexe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
/**
 * formulaire d'inscription
 *
 * @package    form
 * @subpackage sfGuardUser
 * @author     Lexik
 * @version    SVN: $Id: sfDoctrineFormTemplate.php 6174 2007-11-27 06:22:40Z fabien $
 */
class sfGuardUserFormRegister extends PluginsfGuardUserForm
{
 
  public function configure()
  {
    unset(
      $this['groups_list'],
      $this['permissions_list'],
      $this['algorithm'],
      $this['salt'],
      $this['is_active'],
      $this['is_super_admin'],
      $this['last_login'],
      $this['created_at'],
      $this['updated_at']
    );
 
    $this->widgetSchema['password']     = new sfWidgetFormInputPassword();
    $this->widgetSchema['password_bis'] = new sfWidgetFormInputPassword();
 
    $this->widgetSchema->setLabels(array(
      'username'     => 'Email* :',
      'password'     => 'Mot de passe* :',
      'password_bis' => 'Confirmation* :'
    ));
 
    $this->validatorSchema['username']     = new sfValidatorEmail(array('required' => true), array('invalid' => 'Cet email n\'est pas valide.', 'required' => 'Champ obligatoire.'));
    $this->validatorSchema['password']     = new sfValidatorString(array('required' => true, 'min_length' => 6), array('min_length' => '"%value%" est trop court (%min_length% lettres minimum).', 'required' => 'Champ obligatoire.'));
    $this->validatorSchema['password_bis'] = new sfValidatorString(array('required' => true, 'min_length' => 6), array('min_length' => '"%value%" est trop court (%min_length% lettres minimum).', 'required' => 'Champ obligatoire.'));
 
    $this->mergePostValidator(new sfValidatorSchemaCompare(
      'password',
      sfValidatorSchemaCompare::EQUAL,
      'password_bis',
      array(),
      array('invalid' => 'Les champs doivent être identiques.')
    ));
  }
 
}

Partagez cet article