Monday, February 25, 2019

Add Change Password Functionality to The Basic Authentication in Laravel 5.7

Add Change Password Functionality to The Basic Authentication in Laravel 5.7

Laravel is an excellent PHP framework with many superb features which ease developers’ burden. For example, the built-in authentication alleviates developers’ trouble of making user authentication from the ground up, which is almost a necessity of many web sites.

Only one command to equip the basic authentication:

$ php artisan make:auth

The functionality includes new user registration, user login and reset password.

However, there is one important feature missing: change password.

This article explains the steps to implement the “change password” functionality after the implementation of Laravel basic authentication. It is based on Laravel 5.7.

Few parts added

Adding new functionality concerns as follows:

  • model (has created!)
  • route
  • controller
  • view

In this case, model User has been created. We just take care of the remaining three parts:

route

Firstly, we follow the naming convention and put the ‘password’ prefix before the name of the routes ‘change’.

routes/web.php

Route::get('password/change','Auth\ChangePasswordController@showChangeForm');
Route::post('password/change','Auth\ChangePasswordController@change')->name('password.change');

controller

The controller named as ‘ChangePasswordController’ under the namespace ‘Auth’ is also follows the naming convention of Laravel authentication. Using artisan command to generate the controller we need.

$ php artisan make:controller Auth/ChangePasswordController

app/Http/Controllers/Auth/ChangePasswordController.php

<?php

namespace App\Http\Controllers\Auth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class ChangePasswordController extends Controller
{
  public function __construct() {
    $this->middleware('auth');
  }
}

As you can see, the first function we implement in the controller is the __construct() function. It states the user must be an authenticated user who is qualified to change password.

Two more functions are added as follows:

public function showChangeForm()
public function change()

The showChangeForm() function just shows a form to change password, while the change() function does the changing password job.

public function showChangeForm() {
  return view('auth.passwords.change');
}

Note that auth.passwords.change is due to the password related operations are under the directory ‘auth/passwords’.

Here shows the code for the controller as below:

  • app/Http/Controllers/Auth/ChangePasswordController.php
<?php
namespace App\Http\Controllers\Auth;

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\Request;

class ChangePasswordController extends Controller
{
  public function __construct() {
    $this->middleware('auth');
  }

  public function showChangeForm() {
    return view('auth.passwords.change');   
  }
  
  public function change(Request $request) {
    $current_password = $request->get('current_password');
    $new_password     = $request->get('new_password');
    
    // User authentication check
    if (Hash::check($current_password, Auth::user()->password)) {
      // Current and new password are the same, meaning user does not change password.
      if (strcmp($current_password, $new_password) != 0) { 
        $request->validate([
          'current_password' => 'required',
          'new_password'     => 'required|string|min:6|confirmed',
        ]); 

        // Change password
        $user = Auth::user();
        $user->password = Hash::make($new_password);
        $user->save();
        return redirect('/')->with('message', ['success', 'Password has been updated!']); 
      } else {
        return redirect()->back()->with('message', ['danger', 'New and current password are the same!']);
      }
    } else {
      return redirect()->back()->with('message', ['danger', 'Password incorrect!']);
    }
  }
}

view

Now, we copy and modify from login.blade.php then create a view file change.blade.php under the directory 'resources/views/auth/passwords`.

  • resources/views/auth/passwords/change.blade.php
@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">{{ __('Change Password') }}</div>
        <div class="card-body">
          <form method="POST" action="{{ route('password.change') }}">
            @csrf
            <div class="form-group row">
              <label for="current_password" class="col-md-4 col-form-label text-md-right">
                {{ __('Current Password') }}
              </label>
              <div class="col-md-6">
                <input id="current_password" type="password" 
                  class="form-control{{ $errors->has('current_password') ? ' is-invalid' : '' }}" 
                  name="current_password" value="{{ old('current_password') }}" required autofocus>
                @if ($errors->has('current_password'))
                  <span class="invalid-feedback" role="alert">
                    <strong>{{ $errors->first('current_password') }}</strong>
                  </span>
                @endif
              </div>
            </div>
            <div class="form-group row">
              <label for="new_password" class="col-md-4 col-form-label text-md-right">
                {{ __('New Password') }}
              </label>
              <div class="col-md-6">
                <input id="new_password" type="password" 
                  class="form-control{{ $errors->has('new_password') ? ' is-invalid' : '' }}" 
                  name="new_password" required>
                @if ($errors->has('new_password'))
                  <span class="invalid-feedback" role="alert">
                    <strong>{{ $errors->first('new_password') }}</strong>
                  </span>
                @endif
              </div>
            </div>
            <div class="form-group row">
              <label for="new_password_confirmation" class="col-md-4 col-form-label text-md-right">
                {{ __('Confirm New Password') }}
              </label>
              <div class="col-md-6">
                <input id="new_password_confirmation" type="password" 
                  class="form-control{{ $errors->has('new_password_confirmation') ? ' is-invalid' : '' }}" 
                  name="new_password_confirmation" required>
                @if ($errors->has('new_password_confirmation'))
                  <span class="invalid-feedback" role="alert">
                    <strong>{{ $errors->first('new_password_confirmation') }}</strong>
                  </span>
                @endif
              </div>
            </div>
            <div class="form-group row mb-0">
              <div class="col-md-8 offset-md-4">
                <button type="submit" class="btn btn-primary">
                  {{ __('Change Password') }}
                </button>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
@endsection

Change Password

Note

'new_password' => 'required|string|min:6|confirmed',

Note that in Laravel validation, when ‘confirmed’ validation is activated, the name of the confirmed field must be ‘xxx_confirmation’. For example, the name of the password field is ‘password’, then the name of the confirmed password field has to be ‘password_confirmation’. That is the rule to enable the confirmed validation.

No comments:

Post a Comment