Symfony permet assez facilement de mettre en œuvre des appels Ajax afin de dynamiser vos écrans. Symfony permet également de facilement sécuriser tout ou partie de vos applications via de simples paramétrages. Si l’utilisateur connecté n’a pas le degré suffisant d’autorisation ou si sa session a expirée, il sera automatiquement dirigé, par le filtre de sécurité de Symfony, vers, par exemple, le panneau de login de votre application.
Un effet de bord de ces techniques est que, si l’utilisateur de votre application laisse sa session expirer, puis lance une action Ajax devant rafraichir une partie de son écran, il verra le panneau de connexion apparaitre dans cette zone : effet peu ergonomique garanti !
Voila la technique que j’utilise pour pallier à ce problème. A vrai dire, je ne sais pas si elle correspond à l’état de l’art, mais elle a l’avantage de bien fonctionner sans nécessiter de multiples interventions dans l’application.
1/ Permettre l’évaluation du Javascript dans les templates affichés via des appels AJax
Cela dépend de la librairie Javascript que vous utilisez. Par exemple, avec JQuery, il faudra préciser que le type de donnée retourné est ‘html’. Si vous utilisez les helpers Symfony, il vous faudra ajouter 'script' => true
au tableau d’options passé au helper.
Cette étape n’est pas obligatoire. Elle permet toutefois de rediriger les utilisateurs en Javascript vers le panneau de connexion.
2/ Modifier le code du contrôleur gérant votre panneau de connexion
On va simplement lui dire que, si il est appelé via une requête Ajax, il n’utilise pas la vue habituelle.
Par exemple :
/** * Executes login action * */ public function executeLogin() { if($this->getRequest()->isXmlHttpRequest()) { $this->getResponse()->setStatusCode(401); return 'redirect'; } /* end of the login action code */ }
3/ Créer la vue appelée précédemment
Ici le fichier loginRedirect.php
La route correspondant à l’action de déconnexion @user_logout doit bien sur exister.
Voilà !
Et vous, que pensez vous de cette méthode ?
Il me semble l’avoir déjà lu quelque part cette méthode.
Mais pourquoi tu rediriges vers logout? Faudrait pas le renvoyer vers login plutôt ?
Je n’ai pas précisé que je suis l’auteur de cette méthode – à vrai dire, tout mes collègues l’utilise donc il m’est difficile d’identifier un auteur précis.
Dans l’exemple je redirige vers logout car on peut imaginer que l’action de déconnexion purge les variables de session et les cookies qui pourraient « trainer » et/ou affiche un message indiquant la déconnexion. Mais rediriger vers le login peut aussi fonctionner.
Une autre solution est de traiter le code de retour HTTP côté JS pour faire une action particulière sur réception de code 401 et/ou 403 à l’appel d’une action en Ajax.
Avec sfGuard les codes de retour 401 et 403 sont correctement gérés depuis le changeset suivant : http://trac.symfony-project.com/changeset/6066
Avec prototype, par exemple, on pourrait faire :
new Ajax.Request(‘/your/url’, {
onComplete: function(transport) {
if (401 == transport.status)
// redirection vers le login
}
});
oui, c’est la meilleure solution mais elle nécessite de faite ce travail sur chaque appel JS. Il suffit de l’oublier pour retrouver le pb exposé.
L’idéal c’est de faire les deux peut être (sur l’affichage du panneau de connexion et les appels JS) ?
On peut étendre la classe Ajax.Request afin d’y ajouter une méthode on401 qui sera automatiquement appelée par Prototype (ou une méthode onFailure plus générale avec traitement de l’attribut « status » de la réponse pour gérer les 401).
Du coup on utilisera par exemple un new Ajax.SecureRequest() en lieu et place d’un Ajax.Request() pour les appels vers des pages sécurisées (ou pour tous les appels si on craint d’en oublier).
Pas mal ! C’est la solution grand luxe. Le pb est qu’il faut que la route de redirection soit parsée par PHP ce qui rend les mises en oeuvre moins élégante.
Pourrais-tu donner un peu plus d’informations sur la partie 1/ ?
En fait je ne vois pa ou je dois passer l’argument car visiblement chez cette étape est obligatoire.
Merci d’avance
Cordialement
PS : Mon nom te dit surement quelque chose 🙂
Fabien, par exemple si tu utilises form_remote_tag , il faut faire ainsi :
Olivier, il semble y avoir une petite erreur dans ton billet au paragraphe 1/ :
‘scripts’ => true
En fait la clé « script » doit être au singulier.
Merci pour ce billet très intéressant.
bien vue Jean Marc, je fais la correction dans le billet.
merci beaucoup