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.
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 :
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
/**
* 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.')
));
}
}