Objectif :
Notre objectif dans ce tutoriel est de réaliser une authentification avec Zend_Auth et un formulaire ExtJS qui ressemblera à ça:
Pré-requis
Des connaissances en PHP, Zend Framework en particulier Zend_Auth et le model MVC sont fortement recommandé, pour avoir un aperçu je vous invite à suivre ces tutoriels.
dans ce tutoriel nous allons reprendre l’exemple Débutez avec Zend_Auth qui explique très clairement comment fonctionne le processus d’authentification avec Zend_Auth et nous apporterons les modifications nécessaire pour qu’il puisse interagir avec notre formulaire AJAX.
Mise en œuvre
Pour arriver a notre but, nous aurons besoin de modifier le contrôleur et la vue d’authentification.
Le formulaire
Pour réaliser notre formulaire de login nous aurons besoin du Framework Ajax ExtJs que vous pouvez télécharger librement sur le site officiel qui inclus une licence open source selon l’usage
Une fois que vous avez téléchargé le Framework vous allons mettre celui-ci dans dans le dossier prévu pour les scripts et nous allons créer un nouveau fichier login.js, à la fin votre dossier public aura la structure suivante:
les fichiers styles.css et icon_padlock.png sont la juste pour définir l’icone (le petit cadenas) de la barre de titre de notre fenêtre.
.image_login { padding-left:20px; background:url(../images/icon_padlock.png) no-repeat 1px 0px; } .lbError { color :red; }
code css à rajouter a votre stylesheet.
Ext.onReady( function() { Ext.QuickTips.init(); // Créer une variable qui va contenir notre FormPanel var login = new Ext.FormPanel( { labelWidth :80, url :'auth/login', frame :true, bodyStyle :'padding:5px;', defaultType :'textfield', monitorValid :true, // Création des deux champs nom d'utilisateur et mot de passe // la proprité name est celle qui est envoyez au serveur avec // la méthode POST. items : [ { fieldLabel :'Utilisateur', id :'username', name :'username', allowBlank :false }, { fieldLabel :'Mot de passe', id :'password', name :'password', inputType :'password', allowBlank :false }, { id :'lbError', name :'lbError', cls :'lbError', xtype :'label', text :'', width :160 } ], buttons : [ { text :'Login', formBind :true, // Function lorsque en clique sur le boutton login handler : function() { login.getForm().submit( { method :'POST', waitTitle :'Conexion en cours...', waitMsg :'envoi des données...', success : function(form, action) { if (action && action.result) { var redirect = action.result.link; window.location = redirect; } }, // en cas d'echec de l'autentification . // en renvois à l'utilisateur le motif failure : function(form, action) { login.getComponent('lbError').setText( action.result.msg.text); if (action.result.msg.code == '2') { login.getComponent('username').focus(); } else if (action.result.msg.code == '3') { login.getComponent('password').focus(); } } }); } } ] }); // ici on vas créer une fenetre qui va contenir Notre formPanel var win = new Ext.Window( { layout :'fit', title :'Identifiez vous', iconCls :'image_login', width :300, height :150, closable :false, resizable :false, modal :true, plain :true, border :false, items : [ login ] }); win.show(); });
Le but de ce tutoriel n’est pas de vous montrer comment créer une fiche avec ExtJS mais de voir comment cette fiche va interagir avec l’action d’authentification, si vous voulez avoir plus de détails sur le code ci-dessus je vous recommande de jeter un œil à cet article et ce tutoriel (en anglais).
Néanmoins je tiens a vous expliquer ce qui ce passe lorsque on clique sur le bouton login.
Notre formulaire envoie une requête http avec la méthode POST à l’url indiqué dans la première ligne mise en surbrillance (ligne 8) et attend au retour une réponse au format JSON sucess :true ou sucess:false, nous incluons aussi d’autres informations tel que le lien de redirection en cas de succès ou le text et le code de l’erreur dans la cas contraire.
affichage du formulaire
Pour pouvoir afficher notre formulaire nous devons initialiser le header de notre layout car vous aurais besoin peut être d’utiliser d’autres Widget ExtJs dans votre application.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title><?php echo $this->escape($this->title); ?></title> <link rel="stylesheet" type="text/css" media="screen" href="<?php echo $this->baseUrl();?>/public/css/styles.css" /> <link rel="stylesheet" type="text/css" href="<?php echo $this->baseUrl();?>/public/js/ext/resources/css/ext-all.css"> <script type="text/javascript" src="<?php echo $this->baseUrl();?>/public/js/ext/adapter/ext/ext-base.js"></script> <script type="text/javascript" src="<?php echo $this->baseUrl();?>/public/js/ext/ext-all.js"></script> </head> <body> <div id="content"> <h1><?php echo $this->escape($this->title); ?></h1> <?php echo $this->layout()->content; ?> </div> </body>
ensuite dans l’action index de notre contrôleur auth nous affichons le formulaire
<script type="text/javascript" src="<?php echo $this->baseUrl();?>/Public/Js/login.js"></script>
Vous pouvez maintenant essayez d’afficher votre formulaire, si ce n’est pas le cas vous avez certainement loupé quelque chose.
Une fois que notre formulaire est terminé nous allons nous intéressés au contrôleur qui va faire le plus gros du travail.
<?php class AuthController extends Zend_Controller_Action { public function indexAction() { $this->view->headTitle ( 'Login' ); } public function loginAction() { $this->_helper->layout->disableLayout (); $this->_helper->removeHelper('viewRenderer'); if ($this->_request->isPost ()) { Zend_Loader::loadClass ( 'Zend_Filter_StripTags' ); $f = new Zend_Filter_StripTags ( ); $username = $f->filter ( $this->_request->getPost ( 'username' ) ); $password = $f->filter ( $this->_request->getPost ( 'password' ) ); if (empty ( $username )) { $message = "{success: false, errors: { reason: 'Please provide a username.' }}"; } else { // setup Zend_Auth adapter for a database table Zend_Loader::loadClass ( 'Zend_Auth_Adapter_DbTable' ); $dbAdapter = Zend_Registry::get ( 'dbAdapter' ); $authAdapter = new Zend_Auth_Adapter_DbTable ( $dbAdapter ); $authAdapter->setTableName ( 'users' ); $authAdapter->setIdentityColumn ( 'username' ); $authAdapter->setCredentialColumn ( 'password' ); // Set the input credential values to authenticate against $authAdapter->setIdentity ( $username ); $authAdapter->setCredential ( md5 ( $password ) ); // do the authentication $auth = Zend_Auth::getInstance (); try { $result = $auth->authenticate ( $authAdapter ); switch ($result->getCode ()) { case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND : $message = "{success: false, msg: {text: 'Utilisateur non trouvé !', code: '2'}}"; break; case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID : $message = "{success: false, msg: {text: 'mot de passe incorect', code: '3'}}"; break; case Zend_Auth_Result::SUCCESS : $data = $authAdapter->getResultRowObject ( null, 'password' ); if ($data->UserLevel > 0) { $auth->getStorage ()->write ( $data ); $message = "{success:true, link: '" . $this->_request->getBaseUrl () . "'}"; } else { $result->auth->clearIdentity (); $message = "{success:false, msg: {text: 'non autoriser, code:'2'}}"; } break; } } catch ( Zend_Db_Adapter_Exception $e ) { $message = "{success:false, msg: {text: 'Erreur de conexion, " . $e->getMessage () . "', code:'6'}}"; } catch ( Zend_Exception $e ) { $message = "{success:false, msg: {text: 'Erreur Systeme, " . $e->getMessage () . "', code:'6'}}"; } $this->getResponse ()->clearBody (); $this->getResponse ()->setHeader ( 'Content-Type', 'text/x-json' ); $this->getResponse ()->setBody ( $message ); } } } }
Si nous regardons le code de près nous remarquerons qu'il n'ya pas de grand changement par apport au contrôleur définit dans le tutoriel que je vous est cité au début de cet article.
$this->_helper->layout->disableLayout (); $this->_helper->removeHelper('viewRenderer');
Comme nous l’avons dit précédemment la réponse attendu par notre formulaire doit être au format JSON et ne doit contenir aucun autre caractère, c’est à cet effet que nous devons désactiver le layout de l’action login et le rendu de la form pour évité d’inclure notre entête dans la réponse.
switch ($result->getCode ()) { case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND : $message = "{success: false, msg: {text: 'Utilisateur non trouvé !', code: '2'}}"; break; case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID : $message = "{success: false, msg: {text: 'mot de passe incorect', code: '3'}}"; break; case Zend_Auth_Result::SUCCESS : $data = $authAdapter->getResultRowObject ( null, 'password' ); if ($data->UserLevel > 0) { $auth->getStorage ()->write ( $data ); $message = "{success:true, link: '" . $this->_request->getBaseUrl () . "'}"; } else { $result->auth->clearIdentity (); $message = "{success:false, msg: {text: 'non autoriser, code:'2'}}"; } break; } } catch ( Zend_Db_Adapter_Exception $e ) { $message = "{success:false, msg: {text: 'Erreur de conexion, " . $e->getMessage () . "', code:'6'}}"; } catch ( Zend_Exception $e ) { $message = "{success:false, msg: {text: 'Erreur Systeme, " . $e->getMessage () . "', code:'6'}}"; }
Dans cette partie nous créons notre chaine JSON selon la réponse de Zend_Auth.
la réponse prend le format {sucess:true, link:’url de redirection’} en cas de succès et {sucess:false,msg{text:’message d’erreur,code:’code erreur’}} en cas d’échec
$this->getResponse ()->clearBody (); $this->getResponse ()->setHeader ( 'Content-Type', 'text/x-json' ); $this->getResponse ()->setBody ( $message );
et finalement nous envoyons la réponse à notre formulaire qui va nous rediriger vers l’url que nous lui avons indiqué ou nous affiche un message d’erreur et nous invite a s’authentifier à nouveau.
Vous pouvez télécharger le code source complet. de l’exemple.
Merci bien pour ce tutoriel mais il ne marche pas (il reste dans l'état "connexion en cours")malgré que j'ai modifié le fichier .ini avec mes propres données et j'ai fait tous les étapes. y 'a t-il un problème ou une faute quelques part, merci de vérifier et nous donner la solution.
RépondreSupprimersalut, y 'a t-il quelqu'un pour repondre a ma question??!!
RépondreSupprimerdésolé je pour ce retard, vous pouvez télécharger le source complet il est fonctionnel, j'ai testé avant de poster.
RépondreSupprimeressai de déboguer avec la console firebug, pour voir votre requete et ça réponse du serveur
Tuto plutot cool un peu de debug mais rien de méchant.
RépondreSupprimerMerci beaucoup pour le partage.
En ce qui me concerne cela ne marche pas, il me met "mot de passe incorrect" alors que je saisi le bon mot de passe dans la bdd
RépondreSupprimerune idée ?
comment est stocké ton mot de passe ? car lors de l'authentification nous attendons un mot haché en MD5
RépondreSupprimersi ton mot de passe est stocké en claire il faudrait remplacer
$authAdapter->setCredential ( md5 ( $password ) );
par
$authAdapter->setCredential ($password);
Merci pour ce tuto. Par contre quand je clique sur Login, j'ai l'erreur suivante sous Firebug : "missing ) in parenthetical" dans ext-all.js ligne 8, et la page reste dans l'état "Connexion en cours".
RépondreSupprimerAvez-vous déjà rencontré ce problème ? Si oui merci de m'en faire-part afin de trouver une solution.
Merci pour ce tuto, mais je rencontre un petit soucis. Il me semble que dans ce cas de figure le mot de passe n'est pas crypté par le client mais par le serveur ce qui signifie qu'il passe en clair sur le réseau. N'est-il pas possible de le crypter via le fichier login.js ?
RépondreSupprimerNice tuto, thanks for sharing
RépondreSupprimerBonjour,
RépondreSupprimerImpossible de faire fonctionner ce tuto,
je suis en ZF 1.11.10
Si quelqu'un a une solution.
Bonjour
RépondreSupprimerj'ai implemente votre application login sous extjs 4 et zend framework zf 1.11.11
j'ai l'erreur sous firebug
action.result is undefined
[Break On This Error]
login.getComponent('lbError').setText(action.result.msg.text);
merci de votre aide. s'est tres urgent merci de vos retours