• 15 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 11/05/2020

L'authentification

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

L'authentification constitue une tâche fréquente. En effet il y a souvent des parties d'un site qui ne doivent être accessibles qu'à certains utilisateurs, ne serait-ce que l'administration. La solution proposée par Laravel est d'une grande simplicité parce que tout est déjà préparé comme nous allons le voir dans ce chapitre.

Artisan

La version 5.0 de Laravel était équipée des vues, assets et routes pour l'authentification. L'arrivée de la version 5.1 a vu la disparition de ces éléments suite à de nombreuses et animées discussions. Finalement avec la version 5.2 on n'a toujours pas tout ça de base mais il y a une commande Artisan pour le générer. Vous allez donc utiliser cette commande :

php artisan make:auth

 Si tout se passe bien vous devriez avoir ces vues :

Les vues de l'authentification

Vous devez aussi trouver un nouveau contrôleur :

Un nouveau contrôleur
Un nouveau contrôleur

Et dans le fichier des routes ce nouveau code :

<?php
Route::auth();
Route::get('/home', 'HomeController@index');

Vous êtes maintenant prêt pour ce chapitre !

Les tables

La table users

Nous allons utiliser la tableusers que nous avons créée au chapitre précédent. Par défaut Laravel considère que cette table existe et il s'en sert comme référence pour l'authentification.

Par défaut également c'est Eloquent qui est utilisé comme driver, il est aussi possible de changer ce fonctionnement.

La table password_reset

Lors de l'installation il existe deux migrations présentes :

Les 2 migrations présentes à l'installation
Les 2 migrations présentes à l'installation

Lors des précédents chapitres je vous ai fait supprimer la seconde parce qu'on avait juste besoin de la table des utilisateurs. Pour ce chapitre on va avoir besoin de la seconde table qui va nous servir pour la réinitialisation des mots de passe.

On va faire un peu le ménage en lançant une commande d'Artisan pour supprimer toutes les tables que vous avez créées :

php artisan migrate:reset

Il ne devrait alors plus vous rester que la tablemigrations vide. Si ce n'est pas le cas faites le nécessaire dans votre base.

Avec les deux migrations présentes lancez alors la commande d'Artisan pour créer les tables :

php artisan migrate

Vous devriez normalement obtenir ceci :

Les 3 tables
Les 3 tables

Maintenant que les tables sont prêtes, passons à la suite.

Les middlewares

C'est quoi un middleware ?

 

Voici un petit schéma pour illustrer cela :

Middleware
Positionnement fonctionnel des middlewares

Un middleware effectue un traitement à l'arrivée de la requête ou à son départ. Par exemple la gestion des sessions ou des cookies dans Laravel se fait dans un middleware, ainsi que l'authentification. On a en fait plusieurs middlewares en pelures d'oignon, chacun effectue son traitement et transmet la requête ou la réponse au suivant.

Laravel s'installe avec deux fichiers middlewares qui concernent l'authentification :

Les middlewares pour l'authentification
Authenticate

Ce middleware permet de savoir si un utilisateur n'est pas authentifié. Voici son code :

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class Authenticate
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);
}
}

On regarde si l'utilisateur est juste un invité (guest). Si c'est le cas on teste si la requête est en Ajax, auquel cas on renvoie  Unauthorized. Si elle n'est pas en Ajax on fait une redirection vers la route  login pour que l'invité puisse s'authentifier. Si ce n'est pas un invité on laisse la requête suivre normalement son cours. Tout cela n'est évidemment pas figé dans le marbre et on peut changer tout ce qu'on veut. Pour ce cours je vais me contenter de prendre le code par défaut.

RedirectIfAuthenticated

Ce middleware permet de savoir si l'utilisateur est ‌authentifié. C'est donc l'exact inverse du précédent. Voici son code :

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/');
}
return $next($request);
}
}

Si l'utilisateur est authentifié, ce qui nous est indiqué par la méthode  check, alors on renvoie à la page de base du site (/). Sinon on laisse la requête suivre normalement son cours.

Routes et contrôleurs

Les routes

On a vu qu'on a créé des routes avec Artisan :

<?php
Route::auth();
Route::get('/home', 'HomeController@index');

Comme ce n'est pas très explicite voyons un peu les routes ainsi créées :

Les routes créées

Nous allons analyser tout ça dans ce chapitre.

Les contrôleurs

Il est fait référence à deux contrôleurs que l'on trouve ici :

Les deux contrôleurs de l'authentification
Les deux contrôleurs de l'authentification
AuthController

Ce contrôleur est destiné à gérer :

  1. l'enregistrement des utilisateurs

  2. la connexion

  3. la déconnexion

Si on regarde son code :

<?php
namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/';
/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware($this->guestMiddleware(), ['except' => 'logout']);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
}

On ne retrouve aucune des méthodes auxquelles il est fait référence dans les routes. Vous pouvez remarquer l'utilisation du trait  Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers. Donc toutes les méthodes se trouvent dans le framework lui-même. Si nous avons besoin de les personnaliser la seule solution est donc de les surcharger.

PasswordController

Ce contrôleur est destiné uniquement à permettre la réinitialisation du mot de passe en cas d'oubli par l'utilisateur. Si on regarde aussi son code :

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class PasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Create a new password controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
}

On se rend compte que lui aussi utilise un trait (Illuminate\Foundation\Auth\ResetsPasswords).

Les vues

Vous allez trouver les vues ici :

Les vues de l'authentification

Vous n'êtes évidemment pas obligé d'utiliser ces vues si vous voulez les intégrer visuellement dans un site (c'est d'ailleurs ce qui sera fait au cours de l'activité de ce chapitre) mais pour ce chapitre on va les utiliser directement. Elles sont toutes conçues de la même manière. Voici par exemple la vue pour la connexion (resources/views/auth/login.blade.php):

@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Login</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
{!! csrf_field() !!}
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" name="remember"> Remember Me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-sign-in"></i>Login
</button>
<a class="btn btn-link" href="{{ url('/password/reset') }}">Forgot Your Password?</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

Évidemment tout est en anglais ! D'autre part on voit qu'on utilise un template (app).

L'enregistrement d'un utilisateur

La validation

Dans le contrôleur AuthController vous trouvez ce code :

<?php
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}

On a vu jusqu'à présent la validation se faire à partir d'une requête de formulaire et là c'est réalisé différemment. Sans doute parce qu'il était difficile pour le framework de gérer correctement les espaces de noms dans ce cas. On trouve aussi dans cette classe une méthode pour créer l'utilisateur :

<?php
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}

Comme on a ajouté une colonneadmin il faut un peu modifier le code pour aussi l'enregistrer :

<?php
public function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'admin' => isset($data['admin'])
]);
}

Le contrôleur

Avant d'envisager une authentification un visiteur doit pouvoir s'enregistrer.

Si on regarde le contenu du trait AuthenticatesAndRegistersUsers on se rend compte qu'il fait appel à deux autres traits :

<?php
namespace Illuminate\Foundation\Auth;
trait AuthenticatesAndRegistersUsers
{
use AuthenticatesUsers, RegistersUsers {
AuthenticatesUsers::redirectPath insteadof RegistersUsers;
AuthenticatesUsers::getGuard insteadof RegistersUsers;
}
}

Il y a deux méthodes dans le trait  RegistersUsers pour l'enregistrement des utilisateurs :

<?php
namespace Illuminate\Foundation\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
trait RegistersUsers
{
use RedirectsUsers;
/**
* Show the application registration form.
*
* @return \Illuminate\Http\Response
*/
public function getRegister()
{
return $this->showRegistrationForm();
}
/**
* Show the application registration form.
*
* @return \Illuminate\Http\Response
*/
public function showRegistrationForm()
{
if (property_exists($this, 'registerView')) {
return view($this->registerView);
}
return view('auth.register');
}
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function postRegister(Request $request)
{
return $this->register($request);
}
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
Auth::guard($this->getGuard())->login($this->create($request->all()));
return redirect($this->redirectPath());
}
/**
* Get the guard to be used during registration.
*
* @return string|null
*/
protected function getGuard()
{
return property_exists($this, 'guard') ? $this->guard : null;
}
}

Voyons de plus près ces deux méthodes :

  • getRegister : ici on renvoie la vue  auth.register qui doit contenir le formulaire pour l'enregistrement (notez qu'il est testé la présence éventuelle d'une propriété  registerView qui permet de changer facilement la localisation et le nom de la vue en créant cette propriété.

  • postRegister : ici on traite la soumission du formulaire, la validation est assurée par la méthode validator qu'on a vue ci-dessus, et si la validation est correcte on crée dans la base cet utilisateur avec la méthode  create, on connecte le nouvel utilisateur avec la méthode  login, enfin on renvoie à l'url définie dans la méthode  redirectPath.

Comme tout ce code se situe dans le framework nous ne devons pas directement le modifier. On peut toutefois modifier l'url de redirection. Regardez la méthode redirectPath placée dans le trait  RedirectUsers :

<?php
public function redirectPath()
{
if (property_exists($this, 'redirectPath'))
{
return $this->redirectPath;
}
return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
}

On teste la présence éventuelle d'une propriété  redirectPath. Si elle est présente on l'utilise pour la redirection. On teste aussi la présence d'une propriété redirectTo, sinon on redirige vers  home. Donc si on veut une redirection spécifique il suffit de créer une propriété redirectPath ou redirectTo dans le contrôleur. Pour toute autre modification on devra surcharger les méthodes.

L'url est  .../register.

La vue auth.register

Il nous faut une vue pour l'enregistrement, on a vu que Laravel nous en propose une. Voici l'aspect normalement obtenu :

Le formulaire pour l'enregistrement

Lorsqu'un utilisateur est créé et connecté il est renvoyé sur la route définie par la fonction  redirectPath qu'on a vue ci-dessus. Comme la route, le contrôleur et la vue sont prévues, on obtient :

Utilisateur enregistré et connecté

La connexion et la déconnexion

Maintenant que les utilisateurs peuvent s'enregistrer passons à la connexion. Par défaut Laravel prévoit de le faire à partir de l'adresse email. On va conserver ce comportement.

La connexion

On a deux méthodes concernées dans le trait AuthenticatesUsers :

<?php
namespace Illuminate\Foundation\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Lang;
trait AuthenticatesUsers
{
use RedirectsUsers;
/**
* Show the application login form.
*
* @return \Illuminate\Http\Response
*/
public function getLogin()
{
return $this->showLoginForm();
}
/**
* Show the application login form.
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm()
{
$view = property_exists($this, 'loginView')
? $this->loginView : 'auth.authenticate';
if (view()->exists($view)) {
return view($view);
}
return view('auth.login');
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function postLogin(Request $request)
{
return $this->login($request);
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
$throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$credentials = $this->getCredentials($request);
if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
return $this->handleUserWasAuthenticated($request, $throttles);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
if ($throttles && ! $lockedOut) {
$this->incrementLoginAttempts($request);
}
return $this->sendFailedLoginResponse($request);
}
/**
* Validate the user login request.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->loginUsername() => 'required', 'password' => 'required',
]);
}
/**
* Send the response after the user was authenticated.
*
* @param \Illuminate\Http\Request $request
* @param bool $throttles
* @return \Illuminate\Http\Response
*/
protected function handleUserWasAuthenticated(Request $request, $throttles)
{
if ($throttles) {
$this->clearLoginAttempts($request);
}
if (method_exists($this, 'authenticated')) {
return $this->authenticated($request, Auth::guard($this->getGuard())->user());
}
return redirect()->intended($this->redirectPath());
}
/**
* Get the failed login response instance.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
protected function sendFailedLoginResponse(Request $request)
{
return redirect()->back()
->withInput($request->only($this->loginUsername(), 'remember'))
->withErrors([
$this->loginUsername() => $this->getFailedLoginMessage(),
]);
}
/**
* Get the failed login message.
*
* @return string
*/
protected function getFailedLoginMessage()
{
return Lang::has('auth.failed')
? Lang::get('auth.failed')
: 'These credentials do not match our records.';
}
/**
* Get the needed authorization credentials from the request.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
protected function getCredentials(Request $request)
{
return $request->only($this->loginUsername(), 'password');
}
/**
* Log the user out of the application.
*
* @return \Illuminate\Http\Response
*/
public function getLogout()
{
return $this->logout();
}
/**
* Log the user out of the application.
*
* @return \Illuminate\Http\Response
*/
public function logout()
{
Auth::guard($this->getGuard())->logout();
return redirect(property_exists($this, 'redirectAfterLogout') ? $this->redirectAfterLogout : '/');
}
/**
* Get the guest middleware for the application.
*/
public function guestMiddleware()
{
$guard = $this->getGuard();
return $guard ? 'guest:'.$guard : 'guest';
}
/**
* Get the login username to be used by the controller.
*
* @return string
*/
public function loginUsername()
{
return property_exists($this, 'username') ? $this->username : 'email';
}
/**
* Determine if the class is using the ThrottlesLogins trait.
*
* @return bool
*/
protected function isUsingThrottlesLoginsTrait()
{
return in_array(
ThrottlesLogins::class, class_uses_recursive(static::class)
);
}
/**
* Get the guard to be used during authentication.
*
* @return string|null
*/
protected function getGuard()
{
return property_exists($this, 'guard') ? $this->guard : null;
}
}

Voyons de plus près ces deux méthodes :

  • getLogin : ici on renvoie la vue  auth.login(sauf s'il existe éventuellement une vue  auth.authenticate ou si on a créé une propriété  loginView) qui doit contenir le formulaire pour la connexion.

  • postLogin : ici on traite la soumission du formulaire, la validation est assurée directement dans la méthode avec la puissante méthode validate qui est une alternative intéressante aux requêtes de formulaires. Si la validation est correcte on vérifie qu'on a pas d'attaque (throttle) puis les données sont vérifiées dans la table avec la méthode  attempt. Si tout va bien on renvoie comme défini par la méthode  handleUserWasAuthenticated, sinon on redirige sur le formulaire avec un message d'erreur défini par la fonction  getFailedLoginMesssage.

Au fil des évolutions de nombreuses fonctions ont été mises en place pour éviter de surcharger dans le contrôleur, pour chaque cas il convient de bien regarder le code pour déterminer la meilleure stratégie à adopter.

L'url est  .../login.

La vue auth.login

Cette vue est aussi prévue. Voici l'aspect du formulaire de connexion :

Le formulaire de connexion

La déconnexion

Dans la barre de menu est prévue la déconnexion :

La commande de déconnexion

Voici la méthode concernée dans le trait  AuthenticatesUsers :

<?php
/**
* Log the user out of the application.
*
* @return \Illuminate\Http\Response
*/
public function getLogout()
{
return $this->logout();
}
/**
* Log the user out of the application.
*
* @return \Illuminate\Http\Response
*/
public function logout()
{
Auth::guard($this->getGuard())->logout();
return redirect(property_exists($this, 'redirectAfterLogout') ? $this->redirectAfterLogout : '/');
}

L'utilisateur est déconnecté avec la méthode  logout et il est ensuite redirigé à la racine du site ou à la route définie par la propriété   redirectAfterLogout si elle existe, sinon vers la racine "/".

L'oubli du mot de passe

Il y a la table  password_resets dans notre base :

La table password_reminders
La table password_resets

On voit qu'on va mémoriser ici l'adresse email, le jeton (token) et le timestamp (par défaut les jetons sont valables pendant une heure).

On a aussi un contrôleur :

Le contrôleur PasswordController

Les URL auront la forme .../password/...

Dans le formulaire de connexion il est prévu un lien en cas d'oubli du mot de passe : 

Le lien pour l'oubli du mot de passe

L'url correspondant est .../password/email

Voici l'aspect du formulaire :

Le formulaire pour l'oubli du mot de passe

On demande à l'utilisateur de saisir son adresse email pour pouvoir le retrouver dans la table des utilisateurs.

Voici le code dans le trait  ResetsPasswords :

<?php
/**
* Display the form to request a password reset link.
*
* @return \Illuminate\Http\Response
*/
public function getEmail()
{
return $this->showLinkRequestForm();
}
/**
* Display the form to request a password reset link.
*
* @return \Illuminate\Http\Response
*/
public function showLinkRequestForm()
{
if (view()->exists('auth.passwords.email')) {
return view('auth.passwords.email');
}
return view('auth.password');
}
/**
* Send a reset link to the given user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function postEmail(Request $request)
{
return $this->sendResetLinkEmail($request);
}
/**
* Send a reset link to the given user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function sendResetLinkEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$broker = $this->getBroker();
$response = Password::broker($broker)->sendResetLink($request->only('email'), function (Message $message) {
$message->subject($this->getEmailSubject());
});
switch ($response) {
case Password::RESET_LINK_SENT:
return $this->getSendResetLinkEmailSuccessResponse($response);
case Password::INVALID_USER:
default:
return $this->getSendResetLinkEmailFailureResponse($response);
}
}

La soumission du formulaire est prévue dans la méthodepostEmail

On a deux cas :

  • L'utilisateur n'est pas valide (l'adresse email n'existe pas) : on redirige sur le formulaire avec le message d'erreur dans la variable  error, avec cet aspect :

Le message d'erreur pour une adresse inconnue
  • l'utilisateur est valide (on lui a envoyé un email) : on redirige sur le formulaire avec le message dans la variable  status.

L'email a bien été envoyé.

C'est quoi la méthode  trans ?

C'est un helper  qui permet d'adapter le texte linguistiquement à partir  de la valeur de la clé  locale dans  config/app.php. Nous verrons cela en détail dans le chapitre sur la localisation.

Pour que l'email soit effectivement envoyé il faut que tout soit bien configuré dans le fichier  .env :

MAIL_DRIVER=smtp
MAIL_HOST=smtp.free.fr
MAIL_PORT=25
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=""

Et dans  config/mail.php :

'from' => array('address' => 'moi@free.fr', 'name' => 'Administrateur'),

La configuration ci-dessus correspond à ma situation en local avec le prestataire  free. Votre cas doit être sans doute différent.

A quoi ressemble l'email envoyé ? Vous trouvez la vue correspondante ici :

La vue pour l'email

Avec ce code :

Click here to reset your password: {{ url('password/reset/'.$token) }}

C'est clair et concis. Voyons ce qu'on obtient en réception :

Click here to reset your password: http://.../password/reset/6e8ad7609e1b7cc5a483d81524ca8443f0138b73

Voyons ce qu'il s'est passé dans la table password_resets : 

La table password_reminders

On a la mémorisation de l'adresse email, du jeton (token) et le moment de la création.

 Si on utilise l'url de l'email on est dirigé sur la route  password/reset et donc sur la méthode  showResetForm du trait  ResetsPasswords :

<?php
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* @param \Illuminate\Http\Request $request
* @param string|null $token
* @return \Illuminate\Http\Response
*/
public function showResetForm(Request $request, $token = null)
{
if (is_null($token)) {
return $this->getEmail();
}
$email = $request->input('email');
if (property_exists($this, 'resetView')) {
return view($this->resetView)->with(compact('token', 'email'));
}
if (view()->exists('auth.passwords.reset')) {
return view('auth.passwords.reset')->with(compact('token', 'email'));
}
return view('auth.reset')->with(compact('token', 'email'));
}

Le jeton est transmis dans la variable $token. On vérifie sa présence sinon on renvoie le formulaire. S'il est présent on retourne le formulaire de saisi du nouveau mot de passe avec la vue  reset dans le dossier  auth/passwords :

La vue de reset

Avec cet aspect :

Le formulaire pour le nouveau mot de passe

À la soumission on tombe sur la méthode postReset  du trait :

<?php
/**
* Reset the given user's password.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function postReset(Request $request)
{
return $this->reset($request);
}
/**
* Reset the given user's password.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function reset(Request $request)
{
$this->validate(
$request,
$this->getResetValidationRules(),
$this->getResetValidationMessages(),
$this->getResetValidationCustomAttributes()
);
$credentials = $request->only(
'email', 'password', 'password_confirmation', 'token'
);
$broker = $this->getBroker();
$response = Password::broker($broker)->reset($credentials, function ($user, $password) {
$this->resetPassword($user, $password);
});
switch ($response) {
case Password::PASSWORD_RESET:
return $this->getResetSuccessResponse($response);
default:
return $this->getResetFailureResponse($request, $response);
}
}

On trouve une validation pour les entrées. Si tout se passe bien le nouveau mot de passe est mémorisé et l'utilisateur connecté. Pour la redirection elle va évidemment dépendre du succès ou de l'échec.

En résumé

  • L'authentification est totalement et simplement prise en charge par Laravel.

  • Un middleware permet d'effectuer un traitement à l'arrivée ou au départ de la requête.

  • On peut utiliser les middlewares Authenticate et  RedirectIfAuthenticated pour autoriser ou interdire un accès.

  • Un système complet de renouvellement du mot de passe est prévu.

Exemple de certificat de réussite
Exemple de certificat de réussite