
Créer un blog – l’authentification
Nous avons dans le précédent article terminé la gestion des commentaires. Nous avons donc l’essentiel du frontend de notre blog mais nous sommes encore loin d’en avoir terminé ! Dans le présent article nous allons changer les vues de l’authentification pour les adapter à notre thème. Ca va être un peu laborieux parce qu’il nous faut pas mal de vues, mais on va s’arranger pour rester suffisamment DRY pour que ça se passe bien !
Vous pouvez télécharger le code final de cet article ici.
Un petit point
Avec Breeze on a installé un dossier avec toutes les vues de l’authentification :
On va conserver ces vues, à part confirm-password et verify-email qui ne nous serviront pas, et juste en changer le code.
On a aussi installé de nombreux composants :
Là on va être sans pitié et on va tous les supprimer (attention à ne pas supprimer le dossier front où on a déjà créé des composants).
On a aussi ces vues :
Ce sont les layouts, la page d’accueil et le dashboard. Là aussi on va se débarrasser de tout ça !
Après ces différentes purges vous devriez n’avoir plus que ces vues :
Vérifiez quand même que votre blog fonctionne encore !
On va aussi supprimer des assets générés pour Breeze (app.css et app.js) :
Cinq composants
On va créer 5 composants pour mutualiser du code et simplifier les vues :
- une alerte pour le statut
- une alerte pour la liste des erreurs de validation
- un input pour l’email
- un input pour le mot de passe
- le bouton de soumission
Pour session-status :
@props(['status']) @if ($status) <div class="alert-box alert-box--info"> <p>{{ $status }}</p> <span class="alert-box__close"></span> </div> @endif
Pour validation-errors :
@props(['errors']) @if ($errors->any()) <div class="alert-box alert-box--error"> <div style="padding-bottom:1rem">@lang('Whoops! Something went wrong.')</div> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> <span class="alert-box__close"></span> </div> @endif
Pour input-email :
@props(['email' => '']) <div> <label for="email">@lang('Email')</label> <input id="email" class="h-full-width" type="email" name="email" placeholder="@lang('Your email')" value="{{ old('email', $email) }}" required autofocus> </div>
Pour input-password :
<div> <label for="password">@lang('Password')</label> <input id="password" class="h-full-width" type="password" name="password" placeholder="@lang('Your password')" required> </div>
Et enfin pour submit :
@props(['title']) <input class="btn--primary h-full-width" type="submit" value="@lang($title)">
La connexion
On va commencer par la page de connexion.
On va changer ainsi le code :
@extends('front.layout') @section('main') <div class="row row-x-center s-styles"> <div class="column large-6 tab-12"> <!-- Session Status --> <x-auth.session-status :status="session('status')" /> <!-- Validation Errors --> <x-auth.validation-errors :errors="$errors" /> <h3 class="h-add-bottom">@lang('Login')</h3> <form class="h-add-bottom" method="POST" action="{{ route('login') }}"> @csrf <!-- Email Address --> <x-auth.input-email /> <!-- Password --> <x-auth.input-password /> <!-- Remember Me --> <label class="h-add-bottom"> <input id="remember_me" type="checkbox" name="remember_me" {{ old('remember_me') ? 'checked' : '' }}> <span class="label-text">@lang('Remember me')</span> </label> <x-auth.submit title="Login" /> <label class="h-add-bottom"> <a href="{{ route('password.request') }}"> @lang('Forgot Your Password?') </a> <a href="{{ route('register') }}" style="float: right;"> @lang('Not registered?') </a> </label> </form> </div> </div> @endsection
Avec l’url monblog.ext/login on obtient maintenant cet aspect :
C’est pas mal mais un chose me gêne : le formulaire est trop collé au footer. On va un peu espacer ça.
On ajoute un règle de style dans public.styles.css :
.s-styles { padding-bottom: var(--vspace-4); }
J’ai déjà ajouté cette classe dans la vue. Du coup c’est plus aéré :
Normalement on doit avoir une alerte en cas de problème :
Et en cas de d’authentification réussie vous tombez maintenant sur une erreur :
Ce qui est logique puisqu’on a supprimé la vue. On voudrait à présent une redirection sur l’accueil du blog. Ca se passe dans RouteServiceProvider, il suffit de changer la valeur de HOME :
public const HOME = '/';
Et ça doit être bon maintenant !
Mais ce qui serait encore mieux c’est de disposer d’un lien vers la page de connexion dans notre barre de navigation. Il faudrait également prévoir la possibilité de se déconnecter. On va compléter le code dans front.layout :
<ul class="s-header__nav"> ... @guest <li {{ currentRoute('login') }}> <a href="{{ route('login') }}">@lang('Login')</a> </li> @else <li> <form action="{{ route('logout') }}" method="POST" hidden> @csrf </form> <a href="{{ route('logout') }}" onclick="event.preventDefault(); this.previousElementSibling.submit();"> @lang('Logout') </a> </li> @endguest </ul>
On a maintenant un lien pour la connexion :
Et quand on est connecté un lien pour se déconnecter :
L’enregistrement
On va s’intéresser à présent à la vue pour l’enregistrement :
@extends('front.layout') @section('main') <div class="row row-x-center s-styles"> <div class="column large-6 tab-12"> <!-- Validation Errors --> <x-auth.validation-errors :errors="$errors" /> <h3 class="h-add-bottom">@lang('Register')</h3> <form class="h-add-bottom" method="POST" action="{{ route('register') }}"> @csrf <!-- Name --> <div> <label for="name">@lang('Name')</label> <input id="name" class="h-full-width" type="text" name="name" placeholder="@lang('Your name')" value="{{ old('name') }}" required autofocus> </div> <!-- Email Address --> <x-auth.input-email /> <!-- Password --> <x-auth.input-password /> <!-- Confirm Password --> <div> <label for="password_confirmation">@lang('Confirm Password')</label> <input id="password_confirmation" class="h-full-width" type="password" name="password_confirmation" placeholder="@lang('Confirm your Password')" required> </div> <x-auth.submit title="Register" /> </form> </div> </div> @endsection
On profite évidemment largement des composants qu’on a créés précédemment. On se retrouve avec un formulaire dans le même style :
La validation devrait fonctionner :
On va également compléter la barre de navigation. mais dans un premier temps on ajoute une commande à Blade (dans AppServiceProvider) :
use Illuminate\Support\Facades\{ Blade, View }; ... public function boot() { ... Blade::if('request', function ($url) { return request()->is($url); }); }
On se sert de cette commande pour compléter le menu :
@guest @request('register') <li class="current"> <a href="{{ request()->url() }}">@lang('Register')</a> </li> @endrequest <li {{ currentRoute('login') }}> <a href="{{ route('login') }}">@lang('Login')</a> </li> @else
J’ai choisi de ne pas faire apparaître systématiquement ce lien d’enregistrement mais juste lorsqu’on affiche le formulaire qui est accessible à partir du formulaire de connexion :
Dès qu’on affiche la page d’enregistrement le lien apparaît dans le menu :
Le renouvellement du mot de passe
La demande
Pour le renouvellement on va remplacer le code de la vue forgot-password :
@extends('front.layout') @section('main') <div class="row row-x-center s-styles"> <div class="column large-6 tab-12"> <!-- Session Status --> <x-auth.session-status :status="session('status')" /> <!-- Validation Errors --> <x-auth.validation-errors :errors="$errors" /> <p class="h-add-bottom">@lang('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.')</p> <form class="h-add-bottom" method="POST" action="{{ route('password.email') }}"> @csrf <!-- Email Address --> <x-auth.input-email /> <x-auth.submit title="Email Password Reset Link" /> </form> </div> </div> @endsection
On va envoyer un email. Pour vos tests le plus efficace est d’utiliser un service comme Mailtrap. Il suffit de renseigner le fichier .env pour que ça fonctionne :
MAIL_MAILER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=xxx MAIL_PASSWORD=xxx MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS=admin@monblog.fr MAIL_FROM_NAME="${APP_NAME}"
On présente un message pour confirmer l’envoi :
Par défaut l’email se présente ainsi :
Pour le moment tout est en anglais mais mettra tout en français à la fin. Comme j’ai bien prévu dans le code la syntaxe adéquate il nous suffira de créer un fichier de traduction global en plus des fichiers de base (validation, pagination, mots de passe…).
Le renouvellement
Pour le renouvellement on va changer le code de la vue reset-password :
@extends('front.layout') @section('main') <div class="row row-x-center s-styles"> <div class="column large-6 tab-12"> <!-- Validation Errors --> <x-auth.validation-errors :errors="$errors" /> <h3 class="h-add-bottom">@lang('Password reset')</h3> <form class="h-add-bottom" method="POST" action="{{ route('password.update') }}"> @csrf <!-- Password Reset Token --> <input type="hidden" name="token" value="{{ $request->route('token') }}"> <!-- Email Address --> <x-auth.input-email :email="$request->email" /> <!-- Password --> <x-auth.input-password /> <!-- Confirm Password --> <div> <label for="password_confirmation">@lang('Confirm Password')</label> <input id="password_confirmation" class="h-full-width" type="password" name="password_confirmation" placeholder="@lang('Confirm your Password')" required> </div> <x-auth.submit title="Reset Password" /> </form> </div> </div> @endsection
Dans le formulaire l’email est déjà renseigné :
Là aussi la validation doit fonctionner :
Si le mot de passe est bien renouvelé on renvoie sur la page de connexion avec un message :
Le renouvellent fonctionne bien mais je trouve dommage de ne pas avoir une indication de cette opération dans le menu. On va donc le compléter (front.layout) :
@guest ... @request('forgot-password') <li class="current"> <a href="{{ request()->url() }}">@lang('Password')</a> </li> @endrequest @request('reset-password/*') <li class="current"> <a href="{{ request()->url() }}">@lang('Password')</a> </li> @endrequest @else
Ainsi on aura un repère dans le menu pendant cette opération :
Conclusion
Voilà on est à jour pour la partie authentification. Le frontend est maintenant bien avancé. Il nous reste peu de chose à code : le formulaire de contact, la partie CMS avec les pages et aussi les liens sociaux. Il nous faudra compléter notre base de données pour gérer tout ça.


19 commentaires
softcode
bonjour bestmomo, merci pour la partie authentification,
j’aimairai avoir une documentation pour un api me permettant d’envoyer des email, non pas sur mailtral mais plutot smtp gmail, donc directement vers la boite gmail de l’utilisateur pour la confirmation, merci beaucoup pour votre aide
bestmomo
Salut,
J’ai rédigé un tuto complet sur le sujet.
softcode
D’accord merci
ngilo
hello BESTMOMO Merci pour ton travail car ça nous aide beaucoup. bonne continuation
softcode
D’accord merci
bensa
Bonjour BESTMOMO,
je recois un message d’erreur en se conncetant sur /login:
View [layouts.guest] not found. (View: C:\wamp64\www\monblog\resources\views\auth\login.blade.php)
svp d’ou vient cette erreur? merci
bestmomo
Bonjour,
Par défaut quand on installe Breeze on a un layout layouts.guest.
Pour le blog on supprime ce layout et on utilise front.layout pour toutes les vues de l’authentification.
Tu dois avoir l’erreur parce que tu as supprimé layouts.guest et pas encore créé les nouvelles vues.
slozano54
Bonjour,
Merci pour ce tuto très instructif.
Je rencontre un problème avec la vue reset-passord.
Laravel m’indique cette erreur :
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
The GET method is not supported for this route. Supported methods: POST.
J’ai donc vérifié que je n’avais rien oublié dans le code du fichier routes.auth.php
Il y a bien une route get avec la méthode create et une route post avec la méthode store.
J’ai comparé avec votre fichier dans l’archive jointe à l’article mais sans succès.
Je suis allé voir dans app.Providers mais sans succès non plus.
Une idée de ce à côté de quoi je suis passé ?
Merci d’avance pour votre réponse.
slozano54
Je pense avoir compris, c’est une erreur d’interprétation de ma part, la vue n’est accessible que via la demande de réinitialisation. Je fais un test et je confirme.
slozano54
C’est bien ça !
bestmomo
Bon, alors problème réglé 😉
slozano54
Oui merci,
je ne sais pourquoi je m’étais mis en tête que la reinitialisation se faisait directement via la route.
%-)
Madz
Bonjour, BESTMOMO, merci infiniment de ton travail et ta passion, j’aurai une question je début laravel, j’ai donc choisis Breeze comme starter pour l’authentification.
Mais pour la customisation de ce dernier je ne m’y retrouve pas assez.
J’aimerais personnalisé le forgot et reset /mot de passe.
Pour les Login : username a la place du mail,
un user a plusieurs adresses mail, (donc dans une table emails où l’adresse mail porte l’user_id)
quand la personne oubli le mot de passe, je lui demande son username + une de ses adresses mail,
et la je rencontre des difficultés pour personnalisé/override le Password::broker() pour qu’il arrête de chercher dans la table user un email.
Merci d’avance BESTMoMo, je sais pas si j’étais assez clair.
bestmomo
Salut,
Dans le contrôleur PasswordResetLinkController tu as ce code :
$request->validate([
'email' => 'required|email',
]);
$status = Password::sendResetLink(
$request->only('email')
);
Par défaut le credential est constitué de l’email, mais là tu peux mettre le nom à la place. Mais je pense que ton souci vient après, avec le système de notification de Laravel. Je pense qu’il faut surcharger la méthode sendResetLink de PasswordBroker pour éviter le fonctionnement normal de la notification qui va forcément planter.
Madz
Merci 😉
oksam
Slt Best j’ai ce souci :
InvalidArgumentException
Unable to locate a class or view for component [auth.session-status].
avec une erreur 500 internal server error
bestmomo
Apparemment Laravel ne trouve pas le composant. Tu l’as bien mis dans le dossier views/components/auth ?
oksam
Cool c’est réglé!
kisarr
Merci de sacrifier votre dimanche pour encore nous satisfaire. Bonne continuation!