Laravel for Beginners: Middleware

Arlind Musliu Portrait
Arlind Musliu

January 8, 2024 · 4 min read · 26 views

Laravel Blogpost Image

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.

What is Laravel Middleware?

Middleware in Laravel is a type of filtering mechanism. 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 Laravel 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.

Creating 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.

An Example Middleware

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.

But, if the site is live, we cannot make the change without losing previous data. We have to write a new migration script that will 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:

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 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 $routeMiddleware array in the app/Http/Kernel.php file:

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel 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<int, class-string|string>
     */
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Illuminate\Http\Middleware\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];

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

        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

    /**
     * The application's middleware aliases.
     *
     * Aliases may be used instead of class names to conveniently assign middleware to routes and groups.
     *
     * @var array<string, class-string|string>
     */
    protected $middlewareAliases = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::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,
        'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
        'signed' => \App\Http\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
		'check.author' => \App\Http\Middleware\CheckAuthorStatus::class,
    ];
}

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;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('/posts/create', [PostController::class, 'create'])->middleware('check.author');

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;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('/admin', [AdminController::class, 'index'])->middleware('role:admin');

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


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!