Password Reset in Multiple Authentication System for Laravel

Password Reset in Multiple Authentication System for Laravel

Hello, everyone. Today I am going to show you the process of implementing a password reset for multiple authentications. Password reset feature is one of the most important features of a project, so it is available out of the box.


Understanding the flow of password reset 

When a user forgets his/her password, they click on the Forgot Your Password button from the login page and is directed to the forget password page. After that, they enter their email address and a verification mail is sent to their email address. When a user clicks on the verification link from their email, they are taken to the change password page. After that, they are asked to filling up the email address and the new password for their account. After filling up the information, the user clicks on the reset password button, and the new password is updated in the database and is redirected to the intended page.


Now, that we have understood the flow of password reset in Laravel let's get into the business. The first and the most important thing is to create controllers for resetting the password.

Create two controllers: AdminResetPasswordController and AdminForgotPasswordController into your directory. You can duplicate the content from the default ResetPasswordController and ForgotPasswordController from the app/Http/Controller/Auth folder.


AdminForgotPasswordController

Copy the following code to the controller:


namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

class AdminForgotPasswordController extends Controller
{
use SendsPasswordResetEmails;

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:admin');
}

public function showLinkRequestForm()
{
return view('auth.passwords.admin-email');
}

//defining which password broker to use, in our case its the admins
protected function broker()
{
return Password::broker('admins');
}
}


Explanation:

The broker function uses the Password facade which allows us to use the admin password broker which we set up on our config/auth.php file while implementing multiple authentications.


My auth.php file:


return [

/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/

'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],

/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/

'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],

'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],

'admin' => [
'driver' => 'session',
'provider' => 'admins',
],

'staff' => [
'driver' => 'session',
'provider' => 'staffs',
],
],

/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/

'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],

'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],

'staffs' => [
'driver' => 'eloquent',
'model' => App\Staff::class,
],
],

/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/

'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
'staffs' => [
'provider' => 'staffs',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],

/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/

'password_timeout' => 10800,

];


Here, the password facade will use the admin broker information which I set on my password array.


AdminResetPasswordController

Copy the following code to the controller:


namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Password;

class AdminResetPasswordController extends Controller
{
use ResetsPasswords;

/**
* Where to redirect users after resetting their password.
*
* @var string
*/
protected $redirectTo = '/admin/dashboard';

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:admin');
}

public function showResetForm(Request $request, $token = null)
{
return view('auth.passwords.admin-reset')
->with(['token' => $token, 'email' => $request->email]);
}


//defining which guard to use in our case, it's the admin guard
protected function guard()
{
return Auth::guard('admin');
}

//defining our password broker function
protected function broker()
{
return Password::broker('admins');
}
}


Admin Password Reset Routes

Route::prefix('admin')->group(function () {
//admin password reset routes
Route::post('/password/email', 'Auth\[email protected]')
->name('admin.password.email');
Route::get('/password/reset', 'Auth\[email protected]')
->name('admin.password.request');
Route::post('/password/reset', 'Auth\[email protected]');
Route::get('/password/reset/{token}', 'Auth\[email protected]')
->name('admin.password.reset');
});


Now, we need to create admin-email.blade.php and admin-reset.blade.php to resources/views/auth/passwords for our admin guard.


admin-email.blade.php

Copy the following code to the file:

@extends('layouts.app')

@section('content')
div class="container">
div class="row justify-content-center">
div class="col-md-8">
div class="card">
div class="card-header">{{ __('Reset Password') }}div>

div class="card-body">
@if (session('status'))
div class="alert alert-success" role="alert">
{{ session('status') }}
div>
@endif

form method="POST" action="{{ route('admin.password.email') }}">
@csrf

div class="form-group row">
label for="email" class="col-md-4 col-form-label text-md-right">

{{ __('E-Mail Address') }}label>

div class="col-md-6">
input id="email" type="email"
class="form-control @error('email') is-invalid @enderror" name="email"
value="{{ old('email') }}" required autocomplete="email" autofocus>

@error('email')
span class="invalid-feedback" role="alert">
strong>{{ $message }}strong>
span>
@enderror
div>
div>

div class="form-group row mb-0">
div class="col-md-6 offset-md-4">
button type="submit" class="btn btn-primary">
{{ __('Send Password Reset Link') }}
button>
div>
div>
form>
div>
div>
div>
div>
div>
@endsection


admin-reset.blade.php

Copy the following code to the file:

@extends('layouts.app')

@section('content')
div class="container">
div class="row justify-content-center">
div class="col-md-8">
div class="card">
div class="card-header">{{ __('Reset Password') }}div>

div class="card-body">
form method="POST" action="{{ route('admin.password.request') }}">
@csrf

input type="hidden" name="token" value="{{ $token }}">

div class="form-group row">
label for="email" class="col-md-4 col-form-label text-md-right">

{{ __('E-Mail Address') }}label>

div class="col-md-6">
input id="email" type="email"
class="form-control @error('email') is-invalid @enderror" name="email"
value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>

@error('email')
span class="invalid-feedback" role="alert">
strong>{{ $message }}strong>
span>
@enderror
div>
div>

div class="form-group row">
label for="password"
class="col-md-4 col-form-label text-md-right">{{ __('Password') }}label>

div class="col-md-6">
input id="password" type="password"
class="form-control @error('password') is-invalid @enderror"
name="password" required autocomplete="new-password">

@error('password')
span class="invalid-feedback" role="alert">
strong>{{ $message }}strong>
span>
@enderror
div>
div>

div class="form-group row">
label for="password-confirm"
class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}label>

div class="col-md-6">
input id="password-confirm" type="password"
class="form-control" name="password_confirmation" required autocomplete="new-password">
div>
div>

div class="form-group row mb-0">
div class="col-md-6 offset-md-4">
button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
button>
div>
div>
form>
div>
div>
div>
div>
div>
@endsection

 

admin-login.blade.php

Add the following code to the file and use it for the admin login.

@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">Admin Logindiv>
div class="panel-body">
form class="form-horizontal" role="form" method="POST"
action="{{ route('admin.login.submit') }}">
{{ csrf_field() }}

div class="form-group{{ $errors->has('email') ? ' has-error' :
'' }}">
label for="email" class="col-md-4 control-label">

E-Mail Addresslabel>

div class="col-md-6">
input id="email" type="email" class="form-control"
name="email" value="{{ old('email') }}" required autofocus>

@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 for="password" class="col-md-4 control-label">

Passwordlabel>

div class="col-md-6">
input id="password" type="password" class="form-control"
name="password" required>

@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"
{{ old('remember') ? 'checked' : '' }}> Remember Me
label>
div>
div>
div>

div class="form-group">
div class="col-md-8 col-md-offset-4">
button type="submit" class="btn btn-primary">
Login
button>

a class="btn btn-link" href="{{ route('admin.password.request') }}">
Forgot Your Password?
a>
div>
div>
form>
div>
div>
div>
div>
div>
@endsection


Create Notification for resetting the password:

Using the command: php artisan make:notification AdminResetPasswordNotification which will be stored inside the app/Notifications folder. 

AdminResetPasswordNotification

Add the following code to the file:


namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class AdminResetPasswordNotification extends Notification
{
use Queueable;

/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($token)
{
$this->token = $token;
}

/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}

/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('You are receiving this email because we recieved a password
reset request for your account.')
->action('Reset Password', route('admin.password.reset', $this->token))
->line('If you did not request a password reset, ignore this email.');
}

/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}


Now, call the notification to your admin model:

public function sendPasswordResetNotification($token)
{
$this->notify(new AdminResetPasswordNotification($token));
}


Now, it's time to test the password reset for your admin guard. You can perform a password reset for your other guards by the same procedure.


Recent comments(1)

Milan
Milan
  • December 10, 2020

Wow. Thanks for the tutorial. I will try to implement a password reset for multiple guards on my pro More ject. You are a gem! Less

Please, Sign In to leave a reply