Deep Dive Into Middlewares In Laravel
Tue, 24 Apr, 2018

Deep Dive Into Middlewares In Laravel

What is a Laravel middleware? It is a feature in Laravel which provides a mechanism for filtering HTTP requests entering your application. This allows you to hook into Laravel request processing work flow to perform some kind of logic that decides how your application works.

What would you use middleware for?

  • Protecting your routes
  • Setting headers on HTTP responses
  • Logging requests to your application
  • Sanitizing incoming parameters
  • Enable site-wide maintenance mode
  • Manipulating responses generated by your application

How to create a custom middleware?

Creating a middleware in Laravel is as simple as running the following command

php artisan make:middleware <MiddlewareName>
//MiddlewareName should be replaced with actual name of the middleware

This creates a middleware with the specified name in the middleware folder located in app. Luckily, Laravel scaffolds the basic things needed to start customizing your middleware.

<?php
namespace AppHttpMiddleware;
use Closure;
class RedirectIfSuperAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
}

Notice the handle function which accepts two parameters $request and $next . The $request parameter holds the incoming request URI in your application while $next parameter is used to pass the request deeper into the application. The logic needed is written within the handle function and that brings us to types of middleware-before middleware and after middleware.

Before middleware as the name suggests handles some set of logic before forwarding the request deeper into the application. On the other hand after middleware runs after the request has been handled by the application and the response built.

Before middleware:

<?php
namespace AppHttpMiddleware;
use Closure;
class RedirectIfSuperAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        //Your logic goes here
        return $next($request);
    }
}

After middleware:

<?php
namespace AppHttpMiddleware;
use Closure;
class RedirectIfSuperAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        //Your logic goes here e.g return redirect('/)

        return $response;
    }
}

Categories of Middleware

  • Global middleware
  • Route middleware

Global middlewares run for every single request that hits the application. Laravel comes with most of these middlewares such as ValidatePostSizeTrimStrings,CheckForMaintenanceMode etc.

Route middlewares run only on routes they are attached to e.g redirectIfAuthenticated.

Registering a Middleware

Any middleware created has to be registered as that is the only way Laravel knows that such exists. To register a middleware simply open the file named kernel.php which is located inside Http folder like so:

This file contains list of all registered middlewares that come with Laravel by default. it contains three major arrays which include $middleware , $middlewareGroups and $routeMiddleware

<?php
namespace AppHttp;
use IlluminateFoundationHttpKernel as HttpKernel;
class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode::class,
        IlluminateFoundationHttpMiddlewareValidatePostSize::class,
        AppHttpMiddlewareTrimStrings::class,
        IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class,
        AppHttpMiddlewareTrustProxies::class,
    ];
    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            AppHttpMiddlewareEncryptCookies::class,
            IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class,
            IlluminateSessionMiddlewareStartSession::class,
            // IlluminateSessionMiddlewareAuthenticateSession::class,
            IlluminateViewMiddlewareShareErrorsFromSession::class,
            AppHttpMiddlewareVerifyCsrfToken::class,
            IlluminateRoutingMiddlewareSubstituteBindings::class,
        ],
        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];
    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => IlluminateAuthMiddlewareAuthenticate::class,
        'auth.basic' => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class,
        'bindings' => IlluminateRoutingMiddlewareSubstituteBindings::class,
        'can' => IlluminateAuthMiddlewareAuthorize::class,
        'guest' => AppHttpMiddlewareRedirectIfAuthenticated::class,
        'throttle' => IlluminateRoutingMiddlewareThrottleRequests::class,
        //the just created middlware
        'superadmin' => AppHttpMiddlewareRedirectIfSuperAdmin::class, 
    ];
}

The $middleware array holds global middlewares which runs for every single HTTP request to the application, so if you want a middleware to run for every request you should register it here. The $middlewareGroups makes it possible to register middlewares in groups making it easier to attach lots of middlewares to a route by using the group name. The $routeMiddlewarearray holds individual registered middlewares.

Assigning a Middleware

Once a middleware is registered it can be attached to a route in two major ways

  • Through the constructor method in a controller
  • Through the route

Middleware assignment through constructor

Middleware assignment via a constructor on a controller gives more flexibility as it offers two important functions except($parameters) and only($parameters) which can be used to prevent or allow the middleware to apply to some helper functions in that controller. Without using the helper functions the middleware applies to every single function on that controller.

<?php
use IlluminateHttpRequest;

class ForumController extends Controller
{

    public function __construct(){
      /**in this case the middleware named auth is applied
       to every single function within this controller
       */
        $this->middleware('auth');
    }

    public function viewForum(){

      return view('index');
    }

    public function edit($id){

    }

    public function delete($id){

    }

}

With the except and only functions we can select which functions the middleware will apply to as shown below:

<?php
use IlluminateHttpRequest;

class ForumController extends Controller
{

    public function __construct(){
      /**the authentication middleware here applies to all functions but
       viewForums() and viewForumDetails() and the opposite of this happens
       when you use only()
       */
        $this->middleware('auth')->except(['viewForums', 'viewForumDetails']);
    }

    public function viewForums(){

      return view('index');
    }

    public function edit($id){

    }

    public function delete($id){

    }

    public function viewForumDetails(){

    }
}

Middleware assignment through routes

Provided a middleware has been registered in can be attached to the route directly as show below:

<?php
//method 1
Route::get('admin/profile', function () {
  //action
})->middleware('auth');

/**method 2
or using the fully qualified class name like so:
*/
use AppHttpMiddlewareCheckAge;

Route::get('admin/profile', function () {
    // action
})->middleware(CheckAge::class);

//method 3
Route::group(['middleware' => ['web']], function () {
    //action
});

N:B Middleware groups can be assigned to a route the same way as a single middleware

Middleware Parameters

Additional parameters can be passed to a middleware. A typical example is where each user id is assigned to a role and the middleware checks the role of a user to determine if he/she has access to the requested URI. Parameters can be passed to a middleware as shown below:

<?php
//First method (Through route)
Route::get('admin/profile', function () {
  //action
})->middleware('auth:<role>'); //<role> here should be replaced by whatever parameter the user intends to pass.

//Second method (Through a controller)
use IlluminateHttpRequest;

class ForumController extends Controller
{

    public function __construct(){
        $this->middleware('auth:<role>');
    }
  }

Multiple parameters can be passed to a middleware by separating each parameter by a comma.

<?php
Route::get('admin/profile', function () {
  //action
})->middleware('auth:<role>,<age>,<country>'); //<role>, <age>, <country> here should be replaced by whatever parameters the user intends to pass.

These parameters are passed to the handle function of the middleware after the $next variable.

<?php
class RedirectIfSuperAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next, $role, $age, $country)
    {   
        //Logic for the middleware using the parsed parameters
        return $next($request);
    }
}

Summary

To create a middleware you go through the following processes

  • Create the middleware with artisan command php artisan make:middleware <Middleware Name>.
  • Register the middleware in kernel.php located in the app→Http folder
  • Write your logic in the created middleware
  • Assign middleware to a route or controller

Conclusion

Laravel middlewares make it easier to protect our routes, sanitize input and do a whole lot of other stuffs without writing so much logic. Checkout the official Laravel documentation here for more features of middlewares and most importantly practice.

Stay Updated

Join the weekly Newsletter and never miss out on what's cooking at Devamplify