IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ SymfonyConsultez toutes les FAQ

Nombre d'auteurs : 17, nombre de questions : 81, dernière mise à jour : 18 juin 2017  Ajouter une question

 

Les questions redondantes se multipliant sur le forum Symfony, nous avons choisi de créer cette FAQ afin de regrouper les questions qui sont posées fréquemment.

Vos remarques et idées sont les bienvenues. Et pourquoi pas votre aide ! S'il vous prend l'envie de tailler votre plus belle plume et de retrousser vos manches, il y a de quoi faire !

SommaireSymfony 1Plugins de Symfony 1sfDoctrineGuardPlugin (6)
précédent sommaire suivant
 

Tout d'abord, commencez par l'installer par la méthode que vous préférez : ligne de commande, un checkout SVN ou manuellement, activez-le dans la configuration de votre projet et reconstruisez votre modèle.

Ensuite, activez ses modules au niveau de chacun des projets qui le requièrent. Pour une application frontend, vous n'aurez besoin que du module d'authentification ; pour le backend, vous voudrez probablement gérer les permissions et les utilisateurs. Pour ce faire, modifiez votre fichier settings.yml au niveau de chaque application.

Pour le backend :

all:
.settings:
enabled_modules: [default, sfGuardGroup, sfGuardUser, sfGuardPermission]

Pour le frontend :

all:
.settings:
enabled_modules: [default, sfGuardAuth]

Notez qu'il est évidemment requis d'activer le module sfGuardAuth pour sécuriser une application Symfony à l'aide de ce plug-in.

Vous pouvez additionnellement ajouter l'option « Se souvenir de moi » en modifiant votre fichier filters.yml comme suit, au niveau de chaque application à sécuriser :

remember_me:
class: sfGuardRememberMeFilter

security: ~


Maintenant, il faut que Symfony pense à utiliser sfDoctrineGuardPlugin pour les formulaires de connexion. À cette fin, ajoutez ces quelques lignes à votre fichier settings.yml, toujours dans l'application à sécuriser :

login_module: sfGuardAuth
login_action: signin

secure_module: sfGuardAuth
secure_action: secure

Dans votre dossier lib, il faut que votre utilisateur dérive de sfGuardSecurityUser pour que le plug-in montre toute sa puissance. Modifiez donc l'héritage de cette classe dans le fichier myUser.class.php :
class myUser extends sfGuardSecurityUser
{
}

Dernière étape de la configuration première du plug-in, il faut ajouter les quelques règles de routage dans le fichier routing.yml, toujours dans l'application à sécuriser :
sf_guard_signin:
url: /login
param: { module: sfGuardAuth, action: signin }

sf_guard_signout:
url: /logout
param: { module: sfGuardAuth, action: signout }

Notez que sfDoctrineGuardPlugin requiert une route @homepage pour la déconnexion d'un utilisateur (il y est automatiquement redirigé). Ces routes sont bien évidemment modifiables et traduisibles en fonction de vos besoins.

Finalement, il faut que votre application ou vos modules requièrent une authentification avant affichage pour que l'usage de ce plug-in soit utile. Ajoutez donc ces quelques lignes dans le fichier security.yml de l'application ou du module à sécuriser :

default:
is_secure: true

Mis à jour le 29 octobre 2015 dourouc05

Vérifiez que le module sfGuardAuth est bien activé, dans le fichier settings.yml :

enabled_modules: [default, sfGuardAuth]

Vérifiez que votre classe myUser dérive bien de sfGuardSecurityUser :

class myUser extends sfGuardSecurityUser
{
}

Finalement, vous pouvez tenter d'ajouter ceci dans votre fichier config/factories.yml :

all:
user:
class: sfGuardSecurityUser

Mis à jour le 29 octobre 2015 dourouc05 Siguillaume

Il est fort possible que vous ne vouliez pas utiliser le système de sfDoctrineGuardPlugin pour la connexion, par exemple parce que vous avez déjà un système de SSO sur votre site, un serveur LDAP pour votre Intranet, etc. sfDoctrineGuardPlugin vous permet de définir une fonction entièrement personnalisée pour déterminer si un utilisateur est correctement authentifié ou non (si vous le voulez, elle peut renvoyer true à tous les utilisateurs, cette méthode n'est pas sans risque).

Vous devez fournir au plug-in une fonction ou une méthode qui, prenant le nom d'utilisateur et le mot de passe entré, renvoie un booléen disant si l'utilisateur a entré des identifiants corrects ou non. Nous développerons ici une classe possédant une méthode statique permettant le login d'un utilisateur.

Premièrement, créez un fichier myLogin.class.php dans le dossier lib de votre application. Voici sa structure :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
 
 
<?php  
  
class myLogin extends sfGuardSecurityUser 
{ 
	public static function checkPassword($username, $password) 
	{ 
		if($username && $password) 
			return true; 
	} 
}
Il vous suffit de réimplémenter la méthode checkPassword() pour qu'elle fonctionne comme attendu.

Maintenant, il faut demander à sfDoctrineGuardPlugin d'utiliser cette méthode pour connecter vos utilisateurs. Cela se fait très simplement dans le fichier de configuration app.yml de votre application :

all:
sf_guard_plugin:
check_password_callable: [myLogin, checkPassword]

Remarquez qu'il faut que l'utilisateur soit dans la table sf_guard_user pour que votre méthode soit appelée.

Mis à jour le 29 octobre 2015 dourouc05

sfDoctrineGuardPlugin souffre d'un grand défaut : pour qu'un utilisateur se connecte, il doit être en base de données, un point c'est tout. Que vous utilisiez une méthode de connexion autre ou non. Cependant, cela peut être détourné sans trop de difficultés. Notez qu'il est inutile de prévoir une méthode de connexion personnalisée, la partie du plug-in l'utilisant sera surchargée.

Tout d'abord, il faut changer un peu le formulaire de connexion pour ajouter notre validateur (qui sera montré juste après) dans la configuration. Notifions-en Symfony dans le fichier de configuration de l'application, app.yml :

all:
sf_guard_plugin_signin_form: myAuthForm

Implémentons déjà ce nouveau formulaire dans un fichier myAuthForm.class.php du dossier lib de votre application :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
 
 
<?php 
  
class myAuthForm extends sfGuardFormSignin 
{ 
    public function configure() 
	{ 
        parent::configure(); 
        $this->validatorSchema->setPostValidator(new sfGuardValidatorCustomUser()); 
    } 
}
Dernière étape, créons ce validateur personnalisé. Il dérivera de sfGuardValidatorUser et n'en réimplémentera qu'une seule méthode, doClean(). Ici, nous nous baserons uniquement sur le retour de la méthode d'authentification externe, rien ou presque ne sera repris du plug-in (si l'utilisateur est déjà en base, nous ne l'ajoutons pas ; sinon, toutes les informations à notre disposition y seront stockées).

sfDoctrineGuardPlugin recherche les utilisateurs par leur pseudo ; nous n'utiliserons que l'identifiant fourni par la méthode externe. Il ne requiert pas de mot de passe pour tenter de valider, nous le ferons.

Ce code est à compléter et à mettre dans un nouveau module sfGuardAuth (un simple dossier suffira), dossier lib, fichier sfGuardValidatorCustomUser.class.php.

Code : Sélectionner tout
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
50
51
52
53
 
 
<?php 
  
class sfGuardValidatorCustomUser extends sfGuardValidatorUser 
{ 
	protected function doClean($values) 
	{ 
		$username = isset($values[$this->getOption('username_field')]) ? $values[$this->getOption('username_field')] : ''; 
		$password = isset($values[$this->getOption('password_field')]) ? $values[$this->getOption('password_field')] : ''; 
  
		// don't allow to sign in with an empty username 
		if ($username && $password) 
		{ 
			// votre méthode de connexion, renvoie $connected si l'utilisateur est connecté 
			// ainsi que toute la série de variables utilisées si l'utilisateur n'est pas déjà en base 
			 
			if($connected) 
			{ 
				// récupérons manuellement si l'utilisateur est déjà en base, grâce à son identifiant 
				$query = Doctrine_Core::getTable('sfGuardUser')->createQuery('u')->where('u.id = ?', $id); 
				$user = $query->fetchOne(); 
				 
				// s'il n'est pas en base, ça ne tardera pas 
				if(! $user) 
				{ 
					$user = new sfGuardUser();  
					$user->setId($id); 
					$user->setFirstName($prenom); 
					$user->setLastName($nom); 
					$user->setEmailAddress($email); 
					$user->setUsername($pseudo); 
					$user->setIsActive(true); 
					$user->setIsSuperAdmin(false); 
					$user->save(); 
					// et l'utilisateur est dans la table !  
				} 
				 
				// on renvoie cet objet utilisateur avec les values passées en paramètre, comme l'original 
				return array_merge($values, array('user' => $user)); 
			} 
		} 
		 
		// si tout ne s'est pas bien passé (pas de nom d'utilisateur, de mot de passe ou d'enregistrement dans la méthode externe) 
		// on fait comme sfDoctrineGuardPlugin et on renvoie une belle exception 
		if ($this->getOption('throw_global_error')) 
		{ 
			throw new sfValidatorError($this, 'invalid'); 
		} 
  
		throw new sfValidatorErrorSchema($this, array($this->getOption('username_field') => new sfValidatorError($this, 'invalid'))); 
	} 
}
Il est possible de récupérer d'autres données de la part de cette méthode externe, comme des groupes à associer. Cette modification est plus triviale.

Mis à jour le 29 octobre 2015 dourouc05 Siguillaume

Quand l'utilisateur change certaines données sur le système de connexion centralisé, il est bien normal qu'elles soient mises à jour dans votre application. Le problème est que cela ne peut pas se faire tout seul, vous ne pouvez pas modifier le système de connexion pour qu'il vous en notifie.
La seule solution restante est de les modifier à chaque connexion. C'est là qu'il devient fort intéressant de référer aux utilisateurs par leur identifiant : ils peuvent changer de pseudo à volonté, leur identifiant ne changera jamais. Ils peuvent bien entendu changer d'autres propriétés, étant moins cruciales pour leur identification elles ne poseront pas de problème.

La plus simple technique à employer : si le pseudo (ou n'importe quelle autre donnée) change dans ce que le système externe d'authentification retourne par rapport à ce qui existe dans la base, alors il y a eu modification. Le code qui en découle est plus long et pénible à écrire que complexe, et se présente sous la forme suivante :

Code : Sélectionner tout
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
 
 
	if($user->getFirstName() != $prenom) 
	{ 
		$user->setFirstName($prenom); 
		$user->save(); 
	} 
	 
	if($user->getLastName() != $nom) 
	{ 
		$user->setLastName($nom); 
		$user->save(); 
	} 
	 
	if($user->getUsername() != $pseudo) 
	{ 
		$user->setUsername($pseudo); 
		$user->save(); 
	} 
	 
	if($user->getEmailAddress() != $email) 
	{ 
		$user->setEmailAddress($email); 
		$user->save(); 
	}
Il est conseillé de mettre ce code juste après la création de l'enregistrement le cas échéant, entouré d'une condition pour gagner légèrement en performances dans le cas de la création de l'utilisateur dans la base (les données étant toutes fraîches, inutiles de déjà les mettre à jour). Pour les autres, c'est un passage obligé, forcément.

Code : Sélectionner tout
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
 
 
<?php 
  
class sfGuardValidatorCustomUser extends sfGuardValidatorUser 
{ 
	protected function doClean($values) 
	{ 
		$username = isset($values[$this->getOption('username_field')]) ? $values[$this->getOption('username_field')] : ''; 
		$password = isset($values[$this->getOption('password_field')]) ? $values[$this->getOption('password_field')] : ''; 
  
		// don't allow to sign in with an empty username 
		if ($username && $password) 
		{ 
			// votre méthode de connexion, renvoie $connected si l'utilisateur est connecté 
			// ainsi que toute la série de variables utilisées si l'utilisateur n'est pas déjà en base 
			// on récupère notamment $connected et $id 
			 
			if($connected) 
			{ 
				// récupérons manuellement si l'utilisateur est déjà en base, grâce à son identifiant 
				$query = Doctrine_Core::getTable('sfGuardUser')->createQuery('u')->where('u.id = ?', $id); 
				$user = $query->fetchOne(); 
				 
				// s'il n'est pas en base, ça ne tardera pas 
				if(! $user) 
				{ 
					$user = new sfGuardUser();  
					$user->setId($id); 
					$user->setFirstName($prenom); 
					$user->setLastName($nom); 
					$user->setEmailAddress($email); 
					$user->setUsername($pseudo); 
					$user->setIsActive(true); 
					$user->setIsSuperAdmin(false); 
					$user->save(); 
					// et l'utilisateur est dans la table !  
				} 
				else 
				{ 
					if($user->getFirstName() != $prenom) 
					{ 
						$user->setFirstName($prenom); 
						$user->save(); 
					} 
					 
					if($user->getLastName() != $nom) 
					{ 
						$user->setLastName($nom); 
						$user->save(); 
					} 
					 
					if($user->getUsername() != $pseudo) 
					{ 
						$user->setUsername($pseudo); 
						$user->save(); 
					} 
					 
					if($user->getEmailAddress() != $email) 
					{ 
						$user->setEmailAddress($email); 
						$user->save(); 
					} 
				} 
				 
				return array_merge($values, array('user' => $user)); 
			} 
		} 
  
		if ($this->getOption('throw_global_error')) 
		{ 
			throw new sfValidatorError($this, 'invalid'); 
		} 
  
		throw new sfValidatorErrorSchema($this, array($this->getOption('username_field') => new sfValidatorError($this, 'invalid'))); 
	} 
}

Mis à jour le 29 octobre 2015 dourouc05 Siguillaume

Il est fort probable que vous puissiez récupérer quelques droits de votre système d'authentification externe. Par exemple, une variable $r, indiquant si un utilisateur appartient ou non à un groupe donné, ce qui lui octroie certains droits. Imaginons que $r corresponde au groupe 42, il vous faudra alors ajouter ce code dans votre validateur personnalisé :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
 
 
if($r) 
{ 
	$perm = new sfGuardUserGroup();  
	$perm->setUserId($id); 
	$perm->setGroupId(42);  
	$perm->save(); 
}
Que faire maintenant si l'utilisateur n'en fait plus partie ? Ajoutons simplement un else ! S'il ne fait pas partie du groupe à sa connexion, c'est qu'on peut supprimer l'enregistrement signalant qu'il est dans ce groupe, si du moins il existe.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
 
if(! $r) 
{ 
	$q = Doctrine_Query::create() 
	    ->delete('sfGuardUserGroup u') 
	    ->where('u.user_id = ?', $id) 
		->andWhere('u.group_id'); 
	$r->execute(); 
}
Comment traiter une liste de groupes auxquels l'utilisateur appartient : pour simplifier la gestion des droits ici, il est idéal que les groupes aient le même nom ou identifiant dans ce que vous récupérez, que ce que sfDoctrineGuardPlugin possède dans la table ad hoc. Le code suivant s'écrit donc :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
 
foreach($groups as $group) 
{ 
	$q = Doctrine_Query::create() 
		->select('g.id') 
		->from('sfGuardGroup g') 
		->where('g.name = ?', $group); 
	$grp = $r->fecthOne(); 
	 
	$perm = new sfGuardUserGroup();  
	$perm->setUser($user); 
	$perm->setGroup($grp);  
	$perm->save(); 
}

Mis à jour le 29 octobre 2015 dourouc05 Siguillaume

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2021 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.