Laravel 11 for Beginners: Registering and using a Middleware

Arlind Musliu Portrait
Arlind Musliu

January 8, 2024 · 6 min read · 250 views

Laravel Middleware example

2024 UPDATE - LARAVEL 11

We're excited to announce that we have updated all of our blog post examples to reflect the new Laravel 11 version! Our previous examples were based on Laravel 10, but with the release of Laravel 11, we wanted to ensure that our readers have access to the most up-to-date information and examples.

What is Laravel Middleware?

Laravel middleware is like the security team for your application. They check the credentials of incoming HTTP requests and decide whether to let them through to your application, hold them for further inspection, or turn them away.

It's a layer that sits between the request and the response. You can use middleware for a variety of tasks, such as authenticating users, logging requests, or even modifying the request before it reaches your application logic.

How the Middleware Works

When a request enters your Laravel application, it goes through a stack of middleware before reaching the route that handles it. After the route's controller does its work, the response generated by the controller also goes through the middleware stack before it's sent back to the user.

Default Laravel Middleware: Web and API

Laravel comes with a set of default middleware that is essential for web and API routes. To use these default middleware, you don't need to register them manually as they are already set up but you are allowed to customize them if needed.

The web middleware group is automatically applied to your routes/web.php file and includes middleware such as EncryptCookies, AddQueuedCookiesToResponse, StartSession, ShareErrorsFromSession, VerifyCsrfToken, and SubstituteBindings. These middleware are responsible for maintaining the state of the web application, handling sessions, CSRF protection, and more.

On the other hand, the API middleware group is applied to your routes/api.php file and includes middleware like ThrottleRequests and SubstituteBindings. The ThrottleRequests middleware is particularly important as it limits the number of requests that can be made to your API within a given time frame, preventing abuse and overloading of your server.

Here's an example of how to include the web middleware group for certain routes:

<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\PostController;

// Applying web middleware to a single route
Route::get('/profile', 'ProfileController@index')->middleware('web');

// Applying web middleware to a group of routes
Route::middleware(['web'])->group(function () {
	Route::get('/posts/create', [PostController::class, 'create']);
	Route::get('/posts/{post}', [PostController::class, 'show']);
});

// Routes without the web middleware
Route::get('/posts', [PostController::class, 'index']);

In the example above, the web middleware is applied to the /profile, /posts/create, and /posts/{post} routes, which means they will have session state, CSRF protection, and more. The /posts route is not using the web middleware, which means it won't have session state or CSRF protection.

Creating a Laravel Middleware

To create a new middleware in Laravel, you can use the Artisan command-line tool:

php artisan make:middleware CheckAuthorStatus

This command generates a new middleware class named CheckAuthorStatus in the app/Http/Middleware directory.

Middleware Example

Let's say we want to create a middleware that checks if the authenticated user is an author before allowing them to create a new blog post.

Here's what our CheckAuthorStatus middleware might look like:

<?php

namespace App\Http\Middleware;

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

class CheckAuthorStatus
{
    public function handle(Request $request, Closure $next)
    {
        if (Auth::check() && Auth::user()->is_author) {
            return $next($request);
        }

        return redirect('home')->with('error', 'Only authors can create a post.');
    }
}

In this middleware, we're checking if the user is authenticated and if they have an is_author property set to true. If they're not an author, we redirect them to the home page with an error message.

For this to work, we need to modify our user migration and add a new column that will modify the state of a user to an author. Since our app is not live yet, we can go ahead and make the change in the migration directly:

<?php

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

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->string('email_verified_at')->nullable();
            $table->string('password');
            $table->boolean('is_author')->default(false);
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('users');
    }
}

We will save it as a boolean value where the default value is false. Then we can run the following command to refresh the migrations that we had before and run our seeders again:

php artisan migrate:fresh --seed

If the site is live, DO NOT RUN that command because it will delete all the previous data. We need to create a new migration script that will only modify the user migration:

php artisan make:migration add_is_author_to_users_table --table=users

Next, you would update the migration file to include the new column:

<?php

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

class AddIsAuthorToUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->boolean('is_author')->default(false);
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('is_author');
        });
    }
}

After creating the migration, run the migration command to update the database without any seeders:

php artisan migrate

Now, your users table has an is_author boolean column that you can use to determine if a user is an author.

Registering the Middleware

After creating middleware, you need to register it in your application before it can be used. Middleware can be registered globally, assigned to routes, or grouped within route groups.

To register middleware, add it to the withMiddleware() array in the bootstrap/app.php file:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
   ->withMiddleware(function (Middleware $middleware) {
        $middleware->alias([
            'checkAuthorStatus' => \App\Http\Middleware\CheckAuthorStatus::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

Now, you can use the check.author middleware in your routes.

Using Middleware in Routes

With our CheckAuthorStatus middleware registered, we can use it in our routes file to protect the route that creates new blog posts:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/posts/create', [PostController::class, 'create'])
					->middleware('checkAuthorStatus');

Now, only users who are authors can access the form to create a new blog post.

Middleware Parameters

Middleware can also receive additional parameters. For example, you might want to have a middleware that checks if a user has a specific role:

<?php 

namespace App\Http\Middleware;

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

class CheckUserRole
{
    public function handle(Request $request, Closure $next, $role)
    {
        if (Auth::check() && Auth::user()->role === $role) {
            return $next($request);
        }

        return redirect('home')->with('error', "You do not have access here.");
    }
}

You can pass the $role parameter to the middleware in your route definition like so:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/admin', [AdminController::class, 'index'])
						->middleware('role:admin');

To make this work, you need to register the middleware just as we did for the CheckAuthorStatus middleware.

However, in this case, you need to do the following:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
   ->withMiddleware(function (Middleware $middleware) {
        $middleware->alias([
            'checkAuthorStatus' => \App\Http\Middleware\CheckAuthorStatus::class,
			'role' => \App\Http\Middleware\CheckUserRole::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();
Laravel best PHP framework

Conclusion

Middleware in Laravel serves as the guardian of your application, ensuring that only valid requests are processed by your routes and controllers. They are incredibly flexible and powerful tools for managing HTTP requests and responses. By using middleware, you can add layers of protection, handle authentication, perform logging, and more, keeping your blog secure and running smoothly. As you become more familiar with Laravel middleware, you'll discover even more ways to enhance the functionality and security of your blog application.

Upcoming Articles in the Series

  1. Laravel for Beginners: Authentication and Authorization

  2. Laravel for Beginners: Events and Listeners

  3. Laravel for Beginners: Collections for Data Handling

This article is part of our series Laravel 11 for Beginners: A Step-by-Step Guide to Learn the Concepts.


Bring Your Ideas to Life 🚀

If you need help with a Laravel project let's get in touch.

Lucky Media is proud to be recognized as a Top Laravel Development Agency

Arlind Musliu Portrait
Arlind Musliu

Cofounder and CFO of Lucky Media

Technologies:

Laravel
Heading Pattern

Related Posts

Stay up to date

Be updated with all news, products and tips we share!