<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://blog.visuaweb.com/index.php/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
  <title>VisuaBlog - symfony sfGuard</title>
  <link>http://blog.visuaweb.com/index.php/</link>
  <description></description>
  <language>fr</language>
  <pubDate>Mon, 15 Dec 2008 20:24:26 +0100</pubDate>
  <copyright></copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Gérer sans sfGuard une ouverture de session utilisateur au sein d'une application Web avec Symfony.</title>
    <link>http://blog.visuaweb.com/index.php/post/2007/12/04/Gerer-sans-sfGuard-une-ouverture-de-session-utilisateur-au-sein-dune-application-Web-avec-Symfony</link>
    <guid isPermaLink="false">urn:md5:e8c6262c4fbf3853e338fe1b8353ef39</guid>
    <pubDate>Tue, 04 Dec 2007 09:18:00 +0100</pubDate>
    <dc:creator>Jeremie Engel</dc:creator>
        <category>Notes techniques</category>
        <category>symfony sfGuard</category>    
    <description>&lt;p&gt;Voici un tutorial pas à pas pour gérer une ouverture de session utilisateur au sein d'une application Web avec Symfony.
De la création de la table dans la base de données au template HTML, normalement, tout y est pour pouvoir le reproduire sans difficultés.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Créer la table dans la base de données&lt;/li&gt;
&lt;li&gt;Saisir le schema de la base dans le fichier /config/schema.yml&lt;/li&gt;
&lt;li&gt;Paramétrer symfony pour qu'il puisse se connecter à votre base de données&lt;/li&gt;
&lt;li&gt;Construire les classes associées à la table users dans l'arborescence de fichiers de Symfony.&lt;/li&gt;
&lt;li&gt;Créer les modules et les controllers de l'application&lt;/li&gt;
&lt;li&gt;Créer la page HTML qui proposera l'ouverture de session à l'utilisateur.&lt;/li&gt;
&lt;li&gt;Travailler sur le fichier myUser.php&lt;/li&gt;
&lt;li&gt;Configurer le controller&lt;/li&gt;
&lt;li&gt;Ajouter un filtre pour identifier automatiquement l'utilisateur dans une session ouverte&lt;/li&gt;
&lt;/ul&gt;    &lt;p&gt;Dans le cadre de ma découverte de Symfony, je me suis d'abord attaché à développer un système d'authentification des utilisateurs. Grâce à leurs noms d'utilisateur et leur mots de passe, les utilisateurs s'identifient pour accéder à des espaces personnels. Dans cette présentation, je me focalise uniquement sur la procédure d'authentification que je présente en pas à pas.&lt;/p&gt;



&lt;h4&gt;Créer la table dans la base de données qui gérera les utilisateurs.&lt;/h4&gt;


&lt;p&gt;Dans mon cas j'utilise Postgresql mais la même définition de table se fait sans problème avec n'importe quel SGBD.&lt;/p&gt;

&lt;pre&gt; CREATE TABLE &quot;public&quot;.&quot;users&quot; (
 &quot;id&quot; SERIAL, 
 &quot;login&quot; VARCHAR(30) NOT NULL, 
 &quot;password&quot; VARCHAR(20) NOT NULL, 
 CONSTRAINT &quot;user_pkey&quot; PRIMARY KEY(&quot;id&quot;)
 ) WITH OIDS;&lt;/pre&gt;



&lt;h4&gt;Saisir le schema de la base dans le fichier &lt;code&gt;/config/schema.yml&lt;/code&gt;&lt;/h4&gt;

&lt;pre&gt; propel:
   users:
     _attributes: { phpName: User }
     id:
     login:              varchar(30)
     password:           varchar(20)&lt;/pre&gt;


&lt;p&gt;Attention de ne pas mettre de tabulation et de bien utiliser des espaces.&lt;/p&gt;


&lt;h4&gt;Paramétrer symfony pour qu'il puisse se connecter à votre base de données&lt;/h4&gt;


&lt;p&gt;Pour cela saisissez les informations de connexion à votre base de données dans le fichier &lt;code&gt;/config/databases.yml&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt; all:
   propel:
     class:          sfPropelDatabase
     param:
       dsn:          pgsql://login:pass@serveur/votrebase&lt;/pre&gt;


&lt;h4&gt;Construire les classes associées à la table &lt;code&gt;users&lt;/code&gt; dans l'arborescence de fichiers de Symfony.&lt;/h4&gt;

&lt;pre&gt; symfony propel-build-model&lt;/pre&gt;

&lt;p&gt;Vérifiez bien que vous avec l'info &lt;code&gt;BUILD FINISHED&lt;/code&gt; à l'issue de la construction, dans le cas contraire, vérifiez bien la saisie du fichier &lt;code&gt;schema.yml&lt;/code&gt; et recommencez la commande &lt;code&gt;symfony propel-build-model&lt;/code&gt;&lt;/p&gt;


&lt;p&gt;A l'issue de la construction, vous devez avoir les fichiers suivants&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt; /lib/model/map
 /lib/model/om
 /lib/model/UserPeer.php -&amp;gt; Gère les collections d'utilisateurs
 /lib/model/User.php -&amp;gt; Classe correspondant à un utilisateur&lt;/pre&gt;


&lt;p&gt;Voilà, à cette étape, Symfony est prêt à recevoir le code pour gérer l'authentification des utilisateurs.&lt;/p&gt;


&lt;h4&gt;Créer les modules et les controllers de l'application&lt;/h4&gt;

&lt;p&gt;Il s'agit là de doter l'application des controllers qui gèreront la fonctionnalité. Dans mon cas, j'ai créé un module &lt;code&gt;main&lt;/code&gt; pour la page par défaut de l'application et un module &lt;code&gt;register&lt;/code&gt; qui se chargera de réceptionner les action d'ouverture et de fermeture de de session.
Dans le répertoire racine de votre projet, il s'agit de saisir les commandes&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt; symfony init-module main
 symfony init-module register&lt;/pre&gt;

&lt;p&gt;Sans oublier d'indiquer à Symfony que le controller par déaut est maintenant &lt;code&gt;main&lt;/code&gt;. Ainsi le fichier &lt;code&gt;/apps/frontend/config/routing.yml&lt;/code&gt; doit présenter les informations suivantes&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt; homepage:
   url:   /
   param: { module: main, action: index }&lt;/pre&gt;


&lt;h4&gt;Créer la page HTML qui proposera l'ouverture de session à l'utilisateur.&lt;/h4&gt;

&lt;p&gt;Dans cet exemple, le formulaire est directement implémenté dans la page d'accueil du site.
Ainsi le fichier &lt;code&gt;/apps/frontend/modules/main/templates/indexSuccess.php&lt;/code&gt; présente les données suivantes&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt; &amp;lt;p align=&quot;center&quot;&amp;gt;
 Utilisateur ID : &amp;lt;?php echo  $this-&amp;gt;getContext()-&amp;gt;getUser()-&amp;gt;getAttribute('user_id'); ?&amp;gt;&amp;lt;br /&amp;gt;
 Utilisateur AUTH : &amp;lt;?php echo ($this-&amp;gt;getContext()-&amp;gt;getUser()-&amp;gt;isAuthenticated())?'oui':'non'; ?&amp;gt;&amp;lt;br /&amp;gt;
 &amp;lt;?php echo form_tag('register/login') ?&amp;gt;
 Username  : &amp;lt;?php echo input_tag('login'); ?&amp;gt;&amp;lt;br /&amp;gt;
 Password  : &amp;lt;?php echo input_tag('password'); ?&amp;gt;&amp;lt;br /&amp;gt;
 &amp;lt;?php echo submit_tag('Login'); ?&amp;gt;
 &amp;lt;/form&amp;gt;
 &amp;lt;a href=&quot;http://blog.visuaweb.com/index.php/post/2007/12/04/&amp;lt;?php echo url_for('register/logout'); ?&amp;gt;&quot;&amp;gt;Logout&amp;lt;/a&amp;gt;
 &amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;On remarque que l'action d'ouverture de session est orienté vers le module &lt;code&gt;register&lt;/code&gt; avec l'action &lt;code&gt;login&lt;/code&gt; et que l'action de fermeture est orientée vers le même module avec l'action &lt;code&gt;logout&lt;/code&gt;.&lt;/p&gt;


&lt;h4&gt;Travailler sur le fichier myUser.php&lt;/h4&gt;

&lt;p&gt;Dans le cadre de Symfony, le fichier &lt;code&gt;/apps/frontend/lib/myUser.php&lt;/code&gt; a une importance toute particulière, il s'agit de la classe qui une fois instanciée et retournée par la méthode &lt;code&gt;$this-&amp;gt;getUser()&lt;/code&gt; d'un controller par exemple. C'est dans cette classe que l'implémentation des méthodes d'ouverture et de fermeture de session va être implémentée.
Ainsi, il s'agit de définir 2 méthodes pour la tentative d'ouverture de session et la fermeture de celle-ci&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt; class myUser extends sfBasicSecurityUser
 {
 	public $user = null;
 
 	public function tryLogin($login, $password) {
 		$c = new Criteria(); 
 		$c-&amp;gt;add(UserPeer::LOGIN, $login);
 		$c-&amp;gt;add(UserPeer::PASSWORD, $password);
 		$this-&amp;gt;user = UserPeer::doSelectOne($c);
 		if ($this-&amp;gt;user) {
 			$this-&amp;gt;setAuthenticated(true);
   		$this-&amp;gt;setAttribute('user_id', $this-&amp;gt;user-&amp;gt;getId());	
 			return true;
 		}
 		return false;
 	}
 	
 	public function Logout() {
 		if ($this-&amp;gt;isAuthenticated()) {
 			$this-&amp;gt;getAttributeHolder()-&amp;gt;remove('user_id');
 			$this-&amp;gt;setAuthenticated(0);
 		}
 	}
 	
 }&lt;/pre&gt;


&lt;p&gt;Dans cette classe, un attribut &lt;code&gt;$user&lt;/code&gt; est définit. Cette attribut recevra une instance de la classe &lt;code&gt;User&lt;/code&gt; précédemment créée correponsant aux données de l'utilisateur en base de données.&lt;/p&gt;


&lt;h4&gt;Configurer le controller&lt;/h4&gt;

&lt;p&gt;Il s'agit maintenant de configurer le controller &lt;code&gt;register&lt;/code&gt;. Le fichier /apps/frontend/modules/register/actions/actions.class.php doit présenter le code suivant&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt; class registerActions extends sfActions
 {
   /**
    * Executes index action
    *
    */
   public function executeIndex()
   {
     $this-&amp;gt;forward('default', 'module');
   }
 
   public function executeLogin() {
	 $this-&amp;gt;getUser()-&amp;gt;tryLogin($this-&amp;gt;getRequestParameter('login'), $this-&amp;gt;getRequestParameter('password'));  
   	$this-&amp;gt;forward('main', 'index');
 }
 
 	public function executeLogout() {
 		$this-&amp;gt;getUser()-&amp;gt;Logout();
 		$this-&amp;gt;forward('main', 'index');
 	}
 }&lt;/pre&gt;


&lt;p&gt;A ce stade, l'authentification utilisateur fonctionne. Seul le problème de l'initialisation de l'utilisateur au sein d'une session ouverte reste à solutionner. Pour cela plusieurs méthodes existent. J'ai choisis d'utiliser les Filtes de Symphony qui permettent en amont et en aval de l'appel des controllers de réaliser des traitements.&lt;/p&gt;


&lt;h4&gt;Ajouter un filtre pour identifier automatique l'utilisateur dans une session ouverte&lt;/h4&gt;

&lt;p&gt;Il s'agit là de créer un fichier &lt;code&gt;/lib/zGlobalUserAuthFilter.php&lt;/code&gt; qui contient le code suivant&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt; class zGlobalUserAuthFilter extends sfFilter {
 	public function execute($filterChain) {
     // Execute this filter only once
 	  if ($this-&amp;gt;isFirstCall()) {
 	  	$user = $this-&amp;gt;getContext()-&amp;gt;getUser();
 	  	if ($user-&amp;gt;isAuthenticated()) {
 	  		$c = new Criteria();
 				$c-&amp;gt;add(UserPeer::ID, $user-&amp;gt;getAttribute('user_id'));
 				$user-&amp;gt;user = UserPeer::doSelectOne($c);
 
 	  	}
 	  }
     // Execute next filter
     $filterChain-&amp;gt;execute();
   }
 
 }&lt;/pre&gt;


&lt;p&gt;et de déclarer le filtre dans le fichier &lt;code&gt;/apps/frontend/config/filters.yml&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt; rendering: ~
 web_debug: ~
 security:  ~
 
 # generally, you will want to insert your own filters here
 zUserAuth:
   class: zGlobalUserAuthFilter
   
 cache:     ~
 common:    ~
 flash:     ~
 execution: ~&lt;/pre&gt;



&lt;h4&gt;C'est terminé&amp;nbsp;!&lt;/h4&gt;

&lt;p&gt;Vous n'avez plus qu'à attaquer votre serveur web, créer un utilisateur dans votre base de données et de vous identifier dans l'appli web.
Il s'agit du minimum pour pouvoir gérer une ouverture de session utilisateur. A partir de ce cadre, il s'agit d'enrichir le code pour gérer par exemple les problèmes d'ouverture de session (mauvais login/pass) ou encore gérer l'expiration de la session. Mais mon intention était juste de présenter le gabarit fonctionnel.&lt;/p&gt;


&lt;p&gt;Si une méthode plus élégante existe, je suis preneur :)&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.visuaweb.com/index.php/post/2007/12/04/Gerer-sans-sfGuard-une-ouverture-de-session-utilisateur-au-sein-dune-application-Web-avec-Symfony#comment-form</comments>
      <wfw:comment>http://blog.visuaweb.com/index.php/post/2007/12/04/Gerer-sans-sfGuard-une-ouverture-de-session-utilisateur-au-sein-dune-application-Web-avec-Symfony#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.visuaweb.com/index.php/feed/rss2/comments/1</wfw:commentRss>
      </item>
    
</channel>
</rss>