FAQ PHP
FAQ PHPConsultez toutes les FAQ
Nombre d'auteurs : 68, nombre de questions : 580, dernière mise à jour : 18 septembre 2021
- Comment installer sfDoctrineGuardPlugin ?
- Je reçois une erreur "Call to undefined method myUser::isAnonymous." après l'installation de sfDoctrineGuardPlugin, que faire ?
- Comment créer sa propre méthode d'authentification pour sfDoctrineGuardPlugin ?
- Comment utiliser un système personnalisé d'authentification avec sfDoctrineGuard sans devoir remplir sa base avec tous les utilisateurs ?
- Comment gérer les changements de données avec un système personnalisé d'authentification avec sfDoctrineGuard ?
- Comment gérer les droits avec une authentification externe dans SfDoctrineGuard?
- Comment gérer les droits avec une authentification externe dans SfDoctrineGuard?
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 projet qui le requiert. 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
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
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 :
<?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.
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 d'avoir déjà prévu tour pour utiliser 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 :
<?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.
<?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.
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 :
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.
<?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'
)));
}
}
Lien : Comment créer sa propre méthode d'authentification pour sfDoctrineGuardPlugin ?
Lien : Comment utiliser un système personnalisé d'authentification avec sfDoctrineGuard sans devoir remplir sa base avec tous les utilisateurs ?
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é
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.
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 :
Lien : Comment installer sfDoctrineGuardPlugin ?
Lien : Comment utiliser un système personnalisé d'authentification avec sfDoctrineGuard sans devoir remplir sa base avec tous les utilisateurs ?