Learn Laravel Middleware

Introduction

Middleware is just a layer before route handler. This layer can make our program much more maintainable and readable. The middleware layer is an extra layer but this extra layer makes our life easy by not repeating the same code again and again.


Do you know route handler!

What is route handler?

Laravel Route Handler

Whenever you call any route then the corresponding method to that route is being called and that method is called as route handler. Route handler could be Method from the Controller also.


Understand with a particle example

Suppose you have a shopping website and there are lots of routes.

  • Some route: Anyone can see some pages.
  • Some route: Only Authenticated user can see some page.

Before ordering anything from the shopping website, you will check if the user is logged in or not. Before adding a product to the cart you will see if the user is authenticated or not.

You are checking if the user is logged in or not on every page which is built for the authenticated users.

Checking of the authentication can be done from the route handler and as well as from the middleware. If we will do the checking using a route handler or controller then your method will look something similar to this.

<?php

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

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


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


Route::get('/order', function(){
  // Check if user if authenticated
    return view('order');
});


Route::get('/profile', function(){
  // Check if user if authenticated
    return view('profile');
});


Route::get('/wallet', function(){
  // Check if user if authenticated
    return view('wallet');
});

Route::get('/return_product', function(){
  // Check if user if authenticated
    return view('return_product');
});


We are checking if the user is authenticated or not and if not authenticated the redirect to the login page. This is being done by 5 lines of code. We are writing these 5 lines in most of the routes which are not good code because there is no code reusability. As the LOC(lines of code) increases maintainability becomes difficult.

If you will use Middleware to solve your problem then you will end up using

  • Writing the authentication Chekiang code once
  • Attaching the Middleware on any route with one line of code.
  • If you want to make some changes to the authentication method then you have to make changes in the middleware once it will be applied to all the routes where you had applied.

Example

In this example, we will create a middleware and check the URL Params. If the URL params are less than an 18 then we will stop the user from accessing that webpage. If the number is greater than 18 then we will show the webpage to the user.

First, if all we will register a new route and show call a view corresponding the route.

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

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

Route::get('/vote', function(){
  // Let's call the view corresponding to the vote page 
  return view('vote');
});

Now let’s create the view, this view will be shown whenever user will send GET request on the /vote url.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
    integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>

    <div style="min-height:50vh;background:#101820;width:100%" class="d-flex align-items-center justify-content-center">
        <h1 class="text-center text-light">
            Thanks for coming to vote
        </h1>
    </div>

    <div style="min-height:50vh;background:#F2AA4C;width:100%" class="d-flex align-items-center justify-content-center">
        <h1 class="text-center text-light">
            Please vote for your leader
        </h1>
    </div>

</body>
</html>

First let’s do without middleware

We want that whenever user sends their age less than 18 then we will strictly don’t show the vote page to them.

User will send the age using the URL Params with the key name age.

When the user will route to then http://localhost:8080/vote?age=16 it will redirect to some other page.

When the user will route to then http://localhost:8080/vote?age=19 it will show the vote page.

So from the above URL, you got the idea that we doing are doing this based on the age value. So, In our /vote route handler, we will get the age and check if it is greater than 18 or not! Based on the age we will decide what to do. Once we achieve this then we will do this using middleware.

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

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

Route::get('/vote', function(){
  $age = request()->age ; 
  if ($age < 18) {
      return redirect('/');
  }else{
    return view('vote');
  }
});

  • $request->age: This line of code will get the code from the URL.

After getting the age, we have added the logic for checking the age. If the age is less than 18 then it will redirect to / else it will show the vote page.

$age = $request->age ; 
if ($age < 18) {
    return redirect('/');
}else{
  return view('vote');
}

We can do this using middleware also, but the question is why to use middleware when we can solve it using middleware. Middleware helps us to an abstraction layer, If we need to do any kind of validation in some of the routes then using middleware is the best to approach because we will write the code once and add middleware to all required routes.

Let’s see how we can do this using middleware.

Create Middleware

Let’s create a middleware using this command.

php artisan make:middleware AgeCheck

When you create the middleware it creates the file in the location app/Hpp/Middleware/. Our middleware name is AgeCheck and it can be found at app/Hpp/Middleware/AgeCheck

When you will open the middleware then you find code similar to this.

We will add our logic in the handler method of this Middleware. Middleware handler method decide weather, what to do with the request before reaching it to the route handler.

<?php

namespace App\Http\Middleware;

use Closure;

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

This line of code is responsible for forwarding the request to the route handler. We want to forward the request to route handler in one case only and that is, when age is not less than 18.

  return $next($request);

Now, We have logic remove the logic from the route handler and put it in the Middleware handler. We have this logic in the route handler.

$age = $request->age ; 
if ($age < 18) {
    return redirect('/');
}else{
  return view('vote');
}

In the middleware, we will add the logic in the route and that logic will decide whether it wants to forward the request to the route handler or not!

We have to make a change which is, Instead of return the view when age is not less than 18 we will forward the request to the route handler and route handler will show the view.

Handler code now looks like this

$age = $request->age ; 
if ($age < 18) {
    return redirect('/');
}else{
  return $next($request);
}

Our Middleware will look something like this.

<?php

namespace App\Http\Middleware;

use Closure;

class AgeCheck
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if($request->age < 18){
            return redirect('/');
        }else{
          return $next($request);
        }
    }
}

Register Middleware

Now you need to attach the middleware with the route but before attaching it to the route we need to register it in the kernal.php

Kernel.php file is very big to include in this article so I am attaching part of it, which will make sense to you. You can understand this also.

I had added one key-value pair at the top in the associated array.

'agecheck' => \App\Http\Middleware\AgeCheck::class

This will register the Middleware and now you can use this middleware in your Laravel app.

protected $routeMiddleware = [        
    'agecheck' => \App\Http\Middleware\AgeCheck::class,
    '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,
];

Attach Middleware to the route

Now we will attach the registered middleware tot the route and we will also remove the logic from it. Now logic is being handled by the middleware.

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

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

Route::get('/vote', function(){
    return view('vote');
})->middleware('agecheck');

You have successfully made your first middleware and now you are can apply this concept in your application also.

Apply the concept of middleware to those places where you are doing a similar kinds of things in various route. You don’t need middleware when you are doing something in one or two routes.


To know more about the Middleware you should watch this video

Video about Laravel Middleware


Thanks for coming to my blog and reading. If you like it then please let me via tweet or comment.

Tweet #nitishk72_