Laravel

Un framework qui rend heureux

Voir cette catégorie
Vers le bas
Voir cette série
Shop : oubli du mot de passe
Lundi 13 janvier 2025 18:30

La mise en place d'un système de réinitialisation de mot de passe est un élément important à prendre en considération lors de la conception d'un site web ou d'une application en ligne. Les utilisateurs peuvent oublier leurs mots de passe pour diverses raisons (absence prolongée, informations sensibles oubliées, etc.). En offrant une fonctionnalité de réinitialisation de mot de passe, vous améliorez l'expérience utilisateur en facilitant leur accès au site ou à l'application.

Vous pouvez trouver le code dans ce dépôt Github.

On va commencer par créer un composant Blade pour les messages en session :

php artisan make:component session-status --view

@props(['status'])

@if ($status)
    <div {{ $attributes->merge(['class' => 'font-medium text-sm text-green-600']) }}>
        {{ $status }}
    </div>
@endif

Pour l'oubli du mot de passe, on crée un composant Volt : 

php artisan make:volt auth/forgot-password --class

Avec ce code :

<?php

use Illuminate\Support\Facades\Password;
use Livewire\Attributes\Title;
use Livewire\Volt\Component;

new
#[Title('Password renewal')]
class extends Component {

	public string $email = '';

	public function sendPasswordResetLink(): void
	{
		$this->validate([
			'email' => ['required', 'string', 'email'],
		]);

		$status = Password::sendResetLink(
			$this->only('email')
		);

		if (Password::RESET_LINK_SENT != $status) {
			$this->addError('email', __($status));

			return;
		}

		$this->reset('email');

		session()->flash('status', __($status));
	}
}; ?>

<div>
    <x-card 
		class="flex justify-center items-center mt-6" 
		title="{{__('Password renewal')}}" 
		subtitle="{{__('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')}}" 
		shadow 
		separator  
		progress-indicator
	>
        <x-session-status class="mb-4" :status="session('status')" />
        <x-form wire:submit="sendPasswordResetLink">
            <x-input 
				label="{{__('Your e-mail')}}" 
				wire:model="email" 
				icon="o-envelope" 
				required 
			/>
			<p class="text-xs text-gray-500"><span class="text-red-600">*</span> @lang('Required information')</p>
            <x-slot:actions>
				<x-button 
					label="{{ __('Back') }}" 
					type="submit" 
					icon="c-arrow-long-left" 
					link="{{ route('login') }}"  
				/>
                <x-button 
					label="{{ __('Email Password Reset Link') }}" 
					type="submit" 
					icon="o-paper-airplane" 
					class="btn-primary" 
				/>
            </x-slot:actions>
        </x-form>
    </x-card>
</div>

Et on ajoute la route, toujours dans le même groupe :

Route::middleware('guest')->group(function () {
	...
	Volt::route('/forgot-password', 'auth.forgot-password');
});

Il ne nous manque plus que les traductions :

"Password renewal": "Renouvellement du mot de passe",
"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.": "Mot de passe oublié ? Pas de problème. Indiquez-nous simplement votre adresse courriel et nous vous enverrons par courriel un lien de réinitialisation du mot de passe pour en choisir un nouveau.",
"Email Password Reset Link": "Envoi du lien de renouvellement",
"Back": "Retour",

Si vous utilisez le formulaire, vous allez tomber sur une erreur à la soumission :

Route [password.reset] not defined.

Et effectivement, on n'a pas encore codé cette partie, alors faisons-le :

php artisan make:volt auth/reset-password --class

Avec ce code :

<?php

use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Support\Facades\{Hash, Password, Session};
use Illuminate\Support\Str;
use Illuminate\Validation\Rules;
use Livewire\Attributes\{Layout, Locked};
use Livewire\Volt\Component;
use App\Rules\StrongPassword;

// Définition du composant avec l'attribut de mise en page
new class extends Component {
	#[Locked]
	public string $token = '';

	public string $email                 = '';
	public string $password              = '';
	public string $password_confirmation = '';

	// Méthode pour initialiser le composant avec le jeton et l'email
	public function mount(string $token): void
	{
		$this->token = $token;

		$this->email = request()->input('email');
	}

	// Méthode pour réinitialiser le mot de passe
	public function resetPassword(): void
	{
		// Validation des données du formulaire
		$this->validate([
			'token'    => ['required'],
			'email'    => ['required', 'string', 'email'],
			'password' => ['required', 'string', 'min:8', 'confirmed', new StrongPassword()],
		]);

		// Réinitialisation du mot de passe
		$status = Password::reset(
			$this->only('email', 'password', 'password_confirmation', 'token'),
			function ($user) {
				$user->forceFill([
					'password'       => Hash::make($this->password),
					'remember_token' => Str::random(60),
				])->save();

				event(new PasswordReset($user));
			}
		);

		// Gestion du statut de la réinitialisation du mot de passe
		if (Password::PASSWORD_RESET != $status) {
			$this->addError('email', __($status));

			return;
		}

		// Affichage du statut de la réinitialisation
		Session::flash('status', __($status));

		// Redirection vers la page de connexion
		$this->redirectRoute('login', navigate: true);
	}
}; ?>

<div>
    <x-card 
		class="flex justify-center items-center mt-6" 
		title="{{__('Reset Password')}}" 
		shadow 
		separator 
		progress-indicator
	>
        <x-session-status class="mb-4" :status="session('status')" />
        <x-form wire:submit="resetPassword">
            <x-input 
				label="{{__('E-mail')}}" 
				wire:model="email" 
				icon="o-envelope"				
				readonly
			/>
            <x-input 
				label="{{__('Password')}}" 
				wire:model="password" 
				type="password" 
				icon="o-key"
                required
				autofocus
			/>
            <x-input 
				label="{{__('Confirm Password')}}" 
				wire:model="password_confirmation" 
				type="password" 
				icon="o-key" 
				required 
				autocomplete="new-password" 
			/>
			<p class="text-xs text-gray-500"><span class="text-red-600">*</span> @lang('Required information')</p>
            <x-slot:actions>
               <x-button 
					label="{{ __('Reset Password') }}" 
					type="submit" 
					icon="o-paper-airplane" 
					class="btn-primary" 
			   />
            </x-slot:actions>
        </x-form>
    </x-card>
</div>

On ajoute la route :

Route::middleware('guest')->group(function () {
	...
	Volt::route('/reset-password/{token}', 'auth.reset-password')->name('password.reset');
});

Il nous manque une traduction :

"Password": "Mot de passe",

Maintenant l'envoi du lien fonctionne et on a un message qui apparaît :

Voici l'aspect de l'email :

En utilisant le lien, on aboutit sur ce formulaire :

Tant qu'à faire, j'ai rendu l'email non modifiable. Après réinitialisation, on se retrouve sur la page de connexion.

Conclusion

Dans ce chapitre, on a créé la logistique pour le renouvellement du mot de passe.



Par bestmomo

Aucun commentaire

Article précédent : Shop : l'authentification
Article suivant : Shop : le compte client 1/2