How to group middleware in Laravel

Updated: January 15, 2024 By: Guest Contributor Post a comment

Introduction

Middleware in Laravel provides a convenient mechanism for filtering HTTP requests entering your application. This feature is particularly useful when you want to perform certain actions like authenticating users, logging requests, or sanitizing input before the request actually handles by controllers and reaches your application’s core. Often, you’ll find yourself applying the same middleware to a group of routes, and Laravel offers an elegant solution for middleware grouping. This tutorial covers the steps and best practices on how to group middleware in Laravel.

Understanding Middleware in Laravel

Let’s start with a basic understanding of what middleware is and how it operates within the Laravel framework. Essentially, middleware acts as a layered system through which HTTP requests must pass. Each layer can examine the request and even modify it before passing it on to the next layer or terminating the execution if necessary.

Example:

// A simple middleware example in Laravel

namespace App\Http\Middleware;

use Closure;

class CheckAge {
    public function handle($request, Closure $next)
    {
        if ($request->age <= 18) {
            return redirect('home');
        }

        return $next($request);
    }
}

Defining Middleware Groups

Middleware groups allow you to assign multiple middleware to a route or a group of routes, thereby reducing the need to repeat common middleware across your routes in Laravel. To define middleware groups, you edit the $middlewareGroups array found in the Kernal.php file within your Laravel application’s app/Http directory.

Example:

// Defining a middleware group in Kernel.php

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // etc...
    ],

    'api' => [
        // 'throttle:api', // Deprecated in favour of scoped middleware
        // Scoped API throttling...
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
    'custom' => [
        \App\Http\Middleware\CheckAge::class,
        \App\Http\Middleware\AnotherMiddleware::class,
    ],
];

Grouping Routes

After defining your middleware groups, you can apply them to routes in your web.php or api.php files that are located within the routes folder. This is achieved by using the middleware method.

Example:

// Assigning the 'custom' middleware group to a group of routes

Route::middleware('custom')->group(function() {
    Route::get('/profile', function() {
        // The 'CheckAge' and 'AnotherMiddleware' will apply here
    });

    Route::get('/settings', function() {
        // The 'CheckAge' and 'AnotherMiddleware' will also apply here
    });
});

Middleware Parameters

In certain cases, you might want to pass parameters to your middleware. This can be defined within the middleware itself and specified while attaching the middleware to a route.

Example:

// Defining middleware with parameters

public function handle($request, Closure $next, $role)
{
    if (!$request->user()->hasRole($role)) {
        // Redirect or handle the unauthorized access
    }
    return $next($request);
}

// Attaching middleware with parameters to a route

Route::get('/admin', function() {
    // ...
})->middleware('role:admin');

In this code snippet, you attach a parameter to the ‘role’ middleware, stipulating that only users with the ‘admin’ role should access the ‘/admin’ route.

Nesting Middleware Groups

Middleware groups can also be nested within other middleware groups if your application requires a more complex middleware layer structure.

Example:

// Nested middleware groups within Kernel.php

protected $middlewareGroups = [
    'web' => [
        // ...existing web middleware...
    ],
    'admin' => [
        'web',
        'auth',
        'role:admin',
    ],
];

// Applying nested middleware groups to routes

Route::middleware('admin')->group(function() {
    // This group of routes will require all middleware in 'web' and 'auth',
    // plus the 'role:admin' middleware
});

Middleware Prioritization

When utilizing middleware groups, the order of middlewares within a group can affect how they’re processed. Laravel allows you to set the priority of middlewares by using the $middlewarePriority array in the Kernel.php file.

Example:

// Setting middleware priority in Kernel.php

protected $middlewarePriority = [
    \App\Http\Middleware\StartSession::class,
    \App\Http\Middleware\Authenticate::class,
    \App\Http\Middleware\PrepareMiddleware::class,
    \App\Http\Middleware\RoleMiddleware::class,
    // Other middlewares...
];

Middlewares for Resource Controllers

When working with resource controllers, you can assign middleware groups to specific actions within those controllers.

Example:

// Using middleware groups in a resource controller

public function __construct() {
    $this->middleware('auth')->except(['index', 'show']);
    $this->middleware('role:admin')->only('create', 'store', 'update', 'delete');
}

This instructs Laravel to apply the ‘auth’ middleware to all methods within a resource controller except for ‘index’ and ‘show’, while the ‘role:admin’ middleware only applies to resource creation, storage, updating, and deleting operations.

Conclusion

Middlewares play a crucial role in any Laravel application, providing a means to pre- and post-process HTTP requests. Middleware grouping makes it easier to manage and assign shared behavior across routes. Leveraging these groups enhances the maintainability and organization of your code, making your Laravel application robust and secure.