Laravel Middleware – A Complete Guide

Laravel Middleware A Complete Guide

Laravel Framework provides a robust mechanism to filter all HTTP requests using the Laravel Middleware classes, the most common example is auth middleware which checks if the current user is logged in or not.

In this post, I will walk you through what is Laravel Middleware and how we can use it to filter down incoming HTTP requests in your application.

As we move on, we will cover how to create custom middleware in Laravel Framework and how we can hook them into the HTTP request life cycle of Laravel so that it can be invoked during the request processing flow.

I hope you have a clear understanding of how to create a Laravel application and use the different features like artisan commands, routes, and controllers.

Before jumping into this topic, let’s understand what are middlewares and what we need to think before using them.

What is a Middleware?

Middleware is a term used by different web frameworks that allow you to hook into the typical request processing flow of an application. During a typical request life cycle, when someone enters your application they use the URL which web frameworks map to a route.

A middleware perform some specific actions on the HTTP request at a specific stage in the HTTP pipeline before or after hitting a user-defined controller action.

A middleware provides an extra layer between the request and response.

In Laravel, we use the term middleware but different languages and frameworks use different terms to implement the same concept. For example, in Laravel, Ruby on Rails and NodeJS we use the term middleware while in Java world, it’s called filters and in C# language calls it delegate handlers.

Laravel Middleware Use Cases

Usage of middleware depends on the nature of applications, some middlewares are passive in their nature like logging middleware. Using middlewares we can change/transform the HTTP headers or can execute some custom business logic functions.

Here are some use cases in the Laravel framework, where middleware is used mostly.

  • Changing site language or locale based on the incoming request.
  • Enabling maintenance mode on your application.
  • Rate-limiting a service request.
  • Writing logs.
  • Tracking the application users.
  • Authorizing certain part of your application to only certain users.
  • Checking for bot traffic.

Laravel ships with some pre-built middleware such as there is a middleware to check for the site maintenance mode, another one is which check and sanitize the input request parameters.

I hope you now have a clear understanding about the Laravel Middleware concept if not, don’t worry in the coming section we will create some custom middleware which will help you to understand how we can use middlewares in a real-world application.

Things to Consider Before Using Middlewares

Here are some of the things which you should consider before jumping on to adding middlewares in your application.

  • Only use the business logic in middlewares which applies to the whole application or part of the application, if your business logic is very specific then better off not using the middlewares.
  • Think about the performance of your application, if you add something which uses a lot of resources then that could cause your entire application.
  • Each middleware gets executed one by one because they reside in the HTTP pipelines. Lightweight middlewares should be triggered before the heavy ones, so middleware ordering is important.
  • Most of the web frameworks are built on top of other frameworks such as Laravel is built on top of Symfony Components, so when you are writing a middleware you are actually writing for the underlying framework. Your middlewares should not cause any conflict with the other components.

Creating Laravel 6 Application

Enough for theory, let’s implement the middlewares in Laravel 6 and see how they get executed. In this Laravel tutorial, I will be showing you how you can implement the protected area for admin users by using the Laravel middleware.

I will start from scratch by creating a new Laravel application. Open your command line terminal and run the below command to make a Laravel 6 application.

composer create-project laravel/laravel LaraMiddleware

Once you have your application ready, head over to the command line terminal again and run below command to add the Laravel UI package which will provide the authentication views (Used to be in the framework but in Laravel 6 you have to require them manually).

composer require laravel/ui --dev

Then run the below command:

php artisan ui vue --auth

This command will scaffold all the views and assets required for this Laravel tutorial.

Updating .env File

Open the .env file and update the database credentials in it.

Upading Laravel Migration for User

Next we will update our User migration file which is located in database/migrations folder. Open the file and add a new field is_admin in it like below:

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->bigIncrements('id');
            $table->boolean('is_admin')->default(0);
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

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

Open the terminal and run the below command to migrate all tables to the database.

php artisan migrate

Generating Users with Laravel Model Factories

For testing purposes, we will also create some users’ records in our database. I will be using the Laravel Model Factory which already comes with the framework.

Open the terminal and enter into the Laravel Tinker.

php artisan tinker

Once you are in the interactive shell, run the below command.

factory('App\User', 10)->create();

The above line of code will create 10 users in the database if everything goes right on your end.

Adding Admin Route to Laravel

Now, if you open the routes/web.php file, you will find the below routes in it.

Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', '[email protected]')->name('home');

As you can see we have already added the authentication routes Auth::routes(), because we ran the php artisan ui vue --auth command earlier.

In this route file, we will add a new route like below.

Route::get('/admin', '[email protected]')->name('admin');

This route is pointing to a new method in our HomeController class named admin. So let’s add that open the HomeController and add the below method in it.

 public function admin()
{
    return view('admin.index');
}

Next, we will add a view in our views folder. Create a new file in resources/views/admin and name it index.blade.php. Update this new file with the below markup.

@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">Admin Area</div>

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

                        You are logged in as admin account!
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Now for testing, run your application and use user information from the database to log in. Upon successful login, you will see the following screen.

Dashboard Page
Dashboard Page

Now, if you go to /admin route you will be presented with the following view.

Admin Page
Admin Page

Our task is to protect this view from any non-admin account holder.

Before proceeding manually change the value of is_admin to 1 for some users in the database.

Generating Laravel Middleware using Artisan Command

Laravel artisan provides a generator command to generate a middleware from the command line terminal. Open the command line terminal and run the below command.

php artisan make:middleware Admin

The above command will generate a middleware class in the app/Http/Middleware folder for you, which will look like below.

namespace App\Http\Middleware;

use Closure;

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

We will update this middleware in the coming section, firstly we need to register this middleware.

Adding Middleware in Kernel.php File

Before using a middleware class, we need to register it the app/Http/Kernel.php file.

There are two ways you can register a middleware:

  • You can register a middleware as a global middleware
  • Or, you can register as a particular route called route middleware.

Open the app/Http/Kernel.php file and register the Admin middleware like below.

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
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,
    'admin' =>  \App\Http\Middleware\Admin::class,
];

You can see our middleware class at the end which we have added against a key name admin.

Updating Our Middleware Class

In this section, we will update the Admin middleware by adding the necessary logic to restrict any non-admin users from certain routes.

Open the Admin middleware class and update the handle() method in it.

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if(auth()->user()->is_admin == 1){
        return $next($request);
    }
    return redirect('home')->with('error','You are not authorised to access admin pages.');
}

In the above method, we are checking if an authenticated user has the admin access or not, if not we are redirecting the user back to /home route.

Using Laravel Middleware in Our Application

If you visit the /admin route, you can access it even if you are not an admin. Because our route is still not protected.

To protect our route we need to use the middleware() method on our route. So update the /admin route like below.

Route::get('/admin', '[email protected]')->name('admin')->middleware('admin');

As you can see, we have chained the middleware() method on our route and passed the admin key which will map to our Admin middleware.

Now, if you visit the /admin URL, you will be redirected back and will be notified with the message like below.

Redirected Using the Admin Middleware
Redirected Using the Admin Middleware

Using Parameters with Middlewares

When using Laravel Middleware in your web application, you might want to pass a parameter to middleware class. A very good example could be a role middleware. Let’s assume we have a role middleware and we would like to check within our middleware which role current users have and based on that role we perform some actions.

For using the parameters in our Admin middleware, we can pass the third parameter $role after $request and $next like below.

Before using this example, you should have a Role model which have a relationship to the User model. Then create a new middleware called Role and update it’s handle() method like below.

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @param $role
 * @return mixed
 */
public function handle($request, Closure $next, $role)
{
    if(auth()->user()->hasRole() == 'admin'){
        return $next($request);
    }

    return redirect('home')->with('error','You are not authorised to access admin pages.');
}

Now we will update the middleware method on our route like below.

Route::get('/admin', '[email protected]')->name('admin')->middleware('role:admin');

Grouped Middlewares

Laravel Middlewares provide an intutive way to group bunch of middlewares togather and you can assign all of them to a single key. To groupe multiple middlewares, we use the $midlewareGroup property in the Kernel.php file. This property takes a key-value pair array. By default Laravel provides a web and api group for middlewares.

 /**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],
];

Conclusion

Laravel Middlewares provides flexibility to execute your custom logic or perform any background action during the request life cycle. When using the middlewares you have to keep some points in mind which mentioned in this post.

If you have any questions or suggestions to improve this post, please leave it in the comments box below.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

When sharing a code snippet please wrap you code with pre tag and add a class code-block to it like below.
<pre class="code-block">you code here</pre>

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.