How to Use Middleware to Implement Simple Super Admin Action in Laravel?

Middleware is a very interesting concept in Laravel. It filters user’s input and passes it next to controller or database. It stops the request, checks it and then passes it.

Implementing this is very easy in Laravel. Let’s suppose we want to implement user roles. Sometimes Super admin doesn’t want to allow the users to login and he wants them to see certain message when they try to login. We can implement this by using middleware. Middleware will literally stop login requests and would check if it’s a user or the admin. Then it will take action. 

1. Installing Laravel

First we need to install Laravel 8 by running this command.

composer create-project --prefer-dist laravel/laravel shop-app

2. Database Configuration

In order to configure the database we need to add these credentials in my .env file.

  • Database name
  • Database password
  • Database username
  • Database host

In order to do so, we will add the following lines in the .env file.

DB_HOST=localhost 
DB_DATABASE=shop-app-db 
DB_USERNAME=root 
DB_PASSWORD=secret

3. Updating User migration

Now we will update user migration. You can find this file “database/migrations” at this location. 

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
	    $table->tinyInteger('is_permission')->default(3);
	    $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Here we added is_permission column. Then run migrations by this command. 
php artisan migrate

3. Creating Vue scaffolding to Login and Register

Run these commands to create login and registration page. 

composer require laravel/ui:^2.4
php artisan ui vue --auth

and then this command to compile css and js files for these pages.

npm install && npm run dev

4. Creating Admin and Super admin by seeder

In order to create admin and super admin add this code in database/seeds/DatabaseSeeder.php

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
	    App\User::create([
		    'name' => 'Emily',
		    'email' => '[email protected]',
		    'password' => \Illuminate\Support\Facades\Hash::make('[email protected]'),
		    'is_permission' => 1
	    ]);

	    App\User::create([
		    'name' => 'Ryan',
		    'email' => '[email protected]',
		    'password' => \Illuminate\Support\Facades\Hash::make('[email protected]'),
		    'is_permission' => 2
	    ]);
    }
}

Then run this command. 

php artisan db:seed

It must create 2 users in database. Emily as admin and Ryan as super admin. You can check by logging in.

5. Registering User

Now go to /register at your site and register a user. It will create first user of the site and he will be logged in automatically. 

6. Creating Meta Migration, Table, Model and Controller

Run this command to create meta table. This table will keep information to decide that users are allowed to login or not. 

php artisan make:migration create_meta_table

now in database/migrations find create meta table file and add this code there. 

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateMetaTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('meta', function (Blueprint $table) {
            $table->id();
	        $table->string('flag');
	        $table->boolean('value');
	        $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('meta');
    }
}

There is a flag to store certain flags like users_allowed_to_login and value will have binary value like 0 or 1. Now run migration once more to create meta table. 

php artisan migrate

Now create model by running following command. 

php artisan make:model Meta

And now add following code in app/Meta.php. 

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Meta extends Model
{
    protected $table = 'meta';	
    protected $fillable = [
		'flag', 'value'
	];
}

And now run following command to create MetaController. 

php artisan make:controller MetaController

We will add code in this controller later. 

7. Creating Helpers file and functions

Now create helpers.php file in app/Http folder. And add this code 

<?php

function users_allowed() {

	if ( get_permission( \Illuminate\Support\Facades\Auth::user()->is_permission ) == 'User' ) {
		if ( sizeof( \App\Meta::where( 'flag', 'user_allowed_to_login' )->get() ) != 0 ) {
			return \App\Meta::where( 'flag', 'user_allowed_to_login' )->first()->value;
		}
	}

	return 1;
}

function returnUsersAllowedStatus() {

	if ( sizeof( \App\Meta::where( 'flag', 'user_allowed_to_login' )->get() ) != 0 ) {
		return \App\Meta::where( 'flag', 'user_allowed_to_login' )->first()->value;
	} else {
		return 1;
	}
}


function get_permission( $id ) {
	if ( $id == 1 ) {
		return 'Super Admin';
	} else if ( $id == 2 ) {
		return 'Admin';
	} else if ( $id == 3 ) {
		return 'User';
	}
}

8. Creating Middleware and registering it

Now create Middleware by using this command. 

php artisan make:middleware AllowUsersToLogin

and Add this code in middleware. 

app/Http/Middlewares/AllowUsersToLogin.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class AllowUsersToLogin {
	/**
	 * Handle an incoming request.
	 *
	 * @param \Illuminate\Http\Request $request
	 * @param \Closure $next
	 *
	 * @return mixed
	 */
	public function handle( $request, Closure $next ) {
		if ( users_allowed() ) {
			return $next( $request );
		}

		Auth::logout();
		return response()->view( 'not-welcome' );
	}
}

Now register it in http/Kernel.php file. 

protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'users-allowed' => \App\Http\Middleware\AllowUsersToLogin::class,
    ];

Then add this middleware in constructor of your HomeController.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('users-allowed');
    }

    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Contracts\Support\Renderable
     */
    public function index()
    {
        return view('home');
    }
}

9. Updating and Adding new Blade files

Add this to your resources/views/home.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">{{ __('Dashboard') }}</div>

                    <div class="card-body">
                        @if (session('status'))
                            <div class="alert alert-success" role="alert">
                                {{ session('status') }}
                            </div>
                        @endif
                        {{ get_permission(\Illuminate\Support\Facades\Auth::user()->id ).' logged in.' }}
                    </div>

                    @if( \Illuminate\Support\Facades\Auth::user()->id == 1 )
                        <div class="card">
                            <div class="card-header">Permissions</div>
                            <div class="card-body">
                                <div class="checkbox">
                                    <label><input id="users_allowed_to_login" type="checkbox" @if(returnUsersAllowedStatus())  checked @endif value=""> Users Allowed to Login</label>
                                </div>
                            </div>
                        </div>
                    @endif
                </div>
            </div>
        </div>
    </div>
@endsection

and create new file as resources/views/not-welcome.blade.php and add this code in there. 

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Laravel</title>

<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@200;600&display=swap" rel="stylesheet">

<!-- Styles -->
<style>
    html, body {
        background-color: #fff;
        color: #636b6f;
        font-family: 'Nunito', sans-serif;
        font-weight: 200;
        height: 100vh;
        margin: 0;
    }

    .full-height {
        height: 100vh;
    }

    .flex-center {
        align-items: center;
        display: flex;
        justify-content: center;
    }

    .position-ref {
        position: relative;
    }

    .top-right {
        position: absolute;
        right: 10px;
        top: 18px;
    }

    .content {
        text-align: center;
    }

    .title {
        font-size: 84px;
    }

    .links > a {
        color: #636b6f;
        padding: 0 25px;
        font-size: 13px;
        font-weight: 600;
        letter-spacing: .1rem;
        text-decoration: none;
        text-transform: uppercase;
    }

    .m-b-md {
        margin-bottom: 30px;
    }
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
    @if (Route::has('login'))
        <div class="top-right links">
            @auth
                <a href="{{ url('/home') }}">Home</a>
            @else
                <a href="{{ route('login') }}">Login</a>

                @if (Route::has('register'))
                    <a href="{{ route('register') }}">Register</a>
                @endif
            @endauth
        </div>
    @endif

    <div class="content">
        <h1 class="m-b-md">
            Sorry Users are not allowed to Login at the Moment. Please try again later.
        </h1>

        <div class="links">
            <a href="https://laravel.com/docs">Docs</a>
            <a href="https://laracasts.com">Laracasts</a>
            <a href="https://laravel-news.com">News</a>
            <a href="https://blog.laravel.com">Blog</a>
            <a href="https://nova.laravel.com">Nova</a>
            <a href="https://forge.laravel.com">Forge</a>
            <a href="https://vapor.laravel.com">Vapor</a>
            <a href="https://github.com/laravel/laravel">GitHub</a>
        </div>
    </div>
</div>
</body>
</html>

10. Adding new JS file, Ajax and compiling it

Create resources/js/meta.js and add following code there. 

$(document).ready(function () {
    $('#users_allowed_to_login').click(function () {
        if ($(this).prop("checked") == true) {
            console.log("Checkbox is checked.");
            setUserAllowedToLogin(1);
        } else if ($(this).prop("checked") == false) {
            console.log("Checkbox is unchecked.");
            setUserAllowedToLogin(0);
        }
    });
});

function setUserAllowedToLogin( value ) {
    var csrf = document.querySelector('meta[name="csrf-token"]').content;
    $.ajax({
        url: 'set-user-allowed-to-login',
        type: "POST",
        data: { 'value': value, '_token': csrf },
        success: function (response) {
            console.log('value set');
        }
    });
}

and then add this in resources/js/app.js file just below where you require bootstrap. 

require('./bootstrap');
require('./meta');

Then compile app.js using this command in root. 

npm run dev

11. Outputs

Now if you will login using email and password “[email protected]” then you will see this. You can enable and disable users login by checking the checkbox. By default users are allowed to login. 

 

and if Super admin will disallow users to login. Then they will see this screen.Â