Laravel 4 : chapitre 16 : Authentification

Il est fréquent d’avoir besoin de filtrer les utilisateurs d’un site selon les pages affichées, les fonctions disponibles… On parle alors d’authentification. Laravel nous offre aussi une infrastructure efficace et facile à mettre en œuvre pour cette partie importante et délicate d’un site.

La table des utilisateurs

La première chose à faire est de créer une table dans  notre base de données pour mémoriser les informations des utilisateurs. En général on se contente d’un pseudonyme, une adresse mail et un mot de passe. Par défaut la table doit se nommer users.  On peut utiliser un autre nom mais ça nous obligerait à effectuer quelques modifications alors autant prendre la valeur par défaut. Commençons par faire une migration pour cette table comme nous l’avons vu lors du chapitre 13 :

img58

Et renseignons notre code pour créer la table et aussi prévoir la marche arrière au cas où (je rappelle que le fichier a été créé dans le dossier database/migrations) :

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsers extends Migration {

  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
      Schema::create('users', function($table) {
          $table->increments('id');
          $table->string('username', 128)->unique();
          $table->string('password', 64);
          $table->string('remember_token', 100)->nullable();
      });
  }

  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
      Schema::drop('users');
  }

}

Vous pouvez changer le nom pour la ligne du pseudo mais ne changez pas celui du mot de passe qui doit être password, ou alors relevez les manches et allez modifier quelques lignes de code Tongue Out. Remarquez aussi que j’ai  précisé que le nom doit être unique, cela va créer automatiquement un index pour celle ligne. Le champ remember_token a été introduit avec la version 4.1.26 de Laravel pour des raisons de sécurité. Il ne reste plus qu’à effectuer la migration :

img59 On vérifie que la table est bien créée :

img64

C’est vraiment la prestation minimale mais ça suffira pour notre exemple. Si vous regardez maintenant dans le dossier app/models vous trouvez un modèle déjà existant nommé User. Si vous l’ouvrez vous trouvez ce code :

use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;

class User extends Eloquent implements UserInterface, RemindableInterface {

	/**
	 * The database table used by the model.
	 *
	 * @var string
	 */
	protected $table = 'users';

	/**
	 * The attributes excluded from the model's JSON form.
	 *
	 * @var array
	 */
	protected $hidden = array('password');

	/**
	 * Get the unique identifier for the user.
	 *
	 * @return mixed
	 */
	public function getAuthIdentifier()
	{
		return $this->getKey();
	}

	/**
	 * Get the password for the user.
	 *
	 * @return string
	 */
	public function getAuthPassword()
	{
		return $this->password;
	}

	/**
	 * Get the token value for the "remember me" session.
	 *
	 * @return string
	 */
	public function getRememberToken()
	{
		return $this->remember_token;
	}

	/**
	 * Set the token value for the "remember me" session.
	 *
	 * @param  string  $value
	 * @return void
	 */
	public function setRememberToken($value)
	{
		$this->remember_token = $value;
	}

	/**
	 * Get the column name for the "remember me" token.
	 *
	 * @return string
	 */
	public function getRememberTokenName()
	{
		return 'remember_token';
	}

	/**
	 * Get the e-mail address where password reminders are sent.
	 *
	 * @return string
	 */
	public function getReminderEmail()
	{
		return $this->email;
	}

}

Laravel est vraiment gentil avec nous !

Insertion d’utilisateurs

On va maintenant créer quelques utilisateurs mais il nous faut un peu parler du mot de passe. Celui-ci doit être crypté pour de raisons de sécurité. Laravel nous propose la classe Hash pour effectuer ce cryptage. Voilà le  code pour ajouter deux utilisateurs :

DB::table('users')->insert(
	array(
		array('username' => 'LeGros', 'password' => Hash::make('passeLeGros')),
		array('username' => 'LeMaigre', 'password' => Hash::make('passeLeMaigre'))
	)
);

Vérifions dans la base :

img61

Le résultat est satisfaisant et les mots de passe sont correctement cryptés.

Un formulaire de connexion

Créons à présent un formulaire de connexion app/views/connexion.php :

<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h2>Connexion au site : </h2>
<?php
    echo Form::open(array('url' => 'connexion'));
    echo '<strong>',Form::label('nom', 'Nom :'),'</strong>';
    echo Form::text('nom');
    echo '<strong>',Form::label('password', 'Mot de passe :'),'</strong>';
    echo Form::password('password');
    echo Form::submit('Se connecter');
    echo Form::close();
?>
</body>
</html>

Et une route :

Route::get('/', function()
{
	return View::make('connexion');
});

Avec l’URL http://localhost/laravel/public on obtient le formulaire :

img62

Traitement de la réponse au formulaire

Entrez ce code dans les routes :

Route::post('connexion', function()
{
	$nom = Input::get('nom');
	$passe = Input::get('password');

	if(Auth::attempt(array('username' => $nom, 'password' => $passe)))
		echo 'Vous êtes maintenant connecté '.Auth::user()->username;
	else
		echo 'Echec de la connexion';
});

On utilise la méthode attempt en passant comme paramètres le mot de passe et le nom. A la place du nom ça pourrait être autre chose comme un mail, l’essentiel étant que cette information soit unique pour identifier l’utilisateur, ce qu’on a prévu dans la table pour les noms. Vous pouvez ajouter d’autres lignes, par exemple pour tester que l’utilisateur est actif, qu’il n’a pas été banni… Dans notre cas si le nom et le mot de passe correspondent alors l’utilisateur est connecté, sinon il ne l’est pas. Laravel prend tout en charge, vous n’avez rien de plus à faire Smile.

Filtrage des utilisateurs

L’intérêt d’une authentification est évidemment de filtrer les utilisateurs pour ne leur donner accès qu’à des ressources autorisées en fonction de leur statut. Voici une route qui applique un filtrage :

Route::get('zone_reservee', array('before' => 'auth', function()
{
    echo 'Vous avez bien été identifié '.Auth::user()->username;
}));

La syntaxe est limpide ! Mais où se trouve ce filtre ? Nous avons vu que tous les filtres se trouvent dans le fichier app/filters, c’est donc ici que nous trouvons les filtres de l’authentification :

Route::filter('auth', function()
{
	if (Auth::guest()) return Redirect::route('login');
});

Route::filter('guest', function()
{
	if (Auth::check()) return Redirect::to('/');
});

On en trouve deux : le premier qu’on a utilisé ci-dessus auth qui vérifie si l’utilisateur est bien authentifié. C’est quoi cet Auth::guest() qu’on trouve à l’intérieur ? Juste une méthode qui renvoie true si l’utilisateur n’est pas authentifié, et vous voyez que dans ce cas on le renvoie à la route login pour qu’il le fasse.

Le second filtre guest fait exactement l’inverse. Il teste que l’utilisateur est authentifié avec Auth::check() et dans ce cas on le renvoie sur le site auquel il a accès.

Maintenant que nous avons analysé ces filtres nous pouvons écrire des routes qui les utilisent, histoire d’avoir quelque chose de fonctionnel :

Route::get('/', array('before' => 'auth', function()
{
	echo 'Maintenant vous êtes sur le site '.Auth::user()->username;
}));

Route::get('login', array('as' => 'login', 'before' => 'guest', function()
{
	return View::make('connexion');
}));

Route::post('connexion', function()
{
	$nom = Input::get('nom');
	$passe = Input::get('password');

	if(Auth::attempt(array('username' => $nom, 'password' => $passe)))
		return Redirect::to('/');
	else
		return Redirect::route('login');
});

Je vous laisse analyser ce code, conjointement avec celui des deux filtres pour comprendre comment tout ça se boucle. Remarquez que j’ai nommé la route login parce que le filtre attend ce nom de route, j’aurais aussi pu changer la syntaxe du filtre mais comme ça vous voyez à nouveau un nommage de route Wink.

Se rappeler de moi

On prévoit souvent sur les sites une option « Se rappeler de moi », pour éviter d’avoir à s’authentifier à nouveau la prochaine fois qu’on visite le site. Ici aussi Laravel nous simplifie la vie. Mais voyons déjà les cookies utilisés pour une authentification simple :

img63

On trouve deux cookies, le premier valide pour la durée de la session et le second valide pendant deux heures. Modifions le code pour avoir l’option « Se rappeler de moi » :

if(Auth::attempt(array('username' => $nom, 'password' => $passe), true))

J’ai juste ajouté un paramètre à la méthode attempt avec la valeur true. Regardons maintenant les cookies quand je me connecte :

img64

On voit apparaître un troisième cookie nommé remember qui expire en 2018 Smile.

Protection CSRF

Il est toujours prudent de se protéger contre le cross-site et Laravel implante systématiquement cette protection pour les formulaires. Regardez le contrôle caché qui a été généré dans le notre :

<input type="hidden" value="7TorWnP8iZUxyeet6z8MfKAZnt8Mz6qKZaSh64pU" name="_token">

Et la route pour le traitement du retour du formulaire :

Route::post('connexion', array('before' => 'csrf', function()
{
	$nom = Input::get('nom');
	$passe = Input::get('password');

	if(Auth::attempt(array('username' => $nom, 'password' => $passe)))
		return Redirect::to('/');
	else
		return Redirect::route('login');
}));

Le jeton (token) est vérifié au niveau du filtre CSRF :

Route::filter('csrf', function()
{
	if (Session::token() != Input::get('_token'))
	{
		throw new Illuminate\Session\TokenMismatchException;
	}
});

On vérifie que le jeton envoyé correspond à celui qui a été placé en session.

On a fait le tour de l’essentiel de l’authentification, vous trouverez des informations complémentaires, comme d’habitude, dans la documentation.

9 réflexions sur “Laravel 4 : chapitre 16 : Authentification

    • bestmomo dit :

      Bonjour,

      Ce chapitre traite de l’authentification, pas de la gestion des utilisateurs, ce qui est un sujet différent.

      Dans mon cours sur le site OpenClassroom j’ai traité une gestion complète des utilisateurs.

      • cavalor dit :

        Salut, il est dommage de devoir passer par Open classroom pour consulter votre cours qu’il pourrait etre pratique d’avoir sous la main. Seriez vous à même de me fournir un pdf de ce cours afin que je le garde sous la main. Je met en place un site pour la premiere fois avec laravel et j’aimerai lire votre ouvrage. Merci d’avance

        • bestmomo dit :

          Salut,

          Malheureusement je n’ai pas de version pdf de mon cours sur Open Classroom. Normalement c’est proposé sur le site, je ne sais pas pourquoi ce n’est pas le cas pour mon cours. Je vais reposer la question.

          Je vous signale que la version 5 devrait sortir en début d’année avec beaucoup d’améliorations. A méditer donc en cas de création actuelle d’un site. On peut déjà parfaitement commencer un développement avec cette version qui commence à se stabiliser.

  1. bestmomo dit :

    Salut !

    Oui l’authentification a évoluée dans les dernières versions, il faut que j’actualise ce chapitre pour en tenir compte.

    Merci.

    Edit : j’ai mis le chapitre à jour pour le modèle User et pour la protection CSRF qui est systématiquement appliquée aux formulaires.

  2. papy2013 dit :

    Un petit bug dans le chapitre Un formulaire de connexion
    Le nom du champ doit être password pour pouvoir être traité dans la route …

    echo '',Form::label('password', 'Mot de passe :'),'';
    echo Form::password('password');

Laisser un commentaire