January 8, 2024 · 6 min read · 250 views
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.
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.
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.
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.
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.
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.
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.
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 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();
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.
This article is part of our series Laravel 11 for Beginners: A Step-by-Step Guide to Learn the Concepts.
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
Technologies:
Related Posts
Stay up to date
Be updated with all news, products and tips we share!