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 App\Http\Middleware;
use Closure;
class RedirectIfSuperAdmin
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $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 App\Http\Middleware;
use Closure;
class RedirectIfSuperAdmin
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
//Your logic goes here
return $next($request);
}
}
After middleware:
<?php
namespace App\Http\Middleware;
use Closure;
class RedirectIfSuperAdmin
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $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 ValidatePostSize
, TrimStrings
,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 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
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::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' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
//the just created middlware
'superadmin' => \App\Http\Middleware\RedirectIfSuperAdmin::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 $routeMiddleware
array 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 Illuminate\Http\Request;
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 Illuminate\Http\Request;
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 App\Http\Middleware\CheckAge;
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 Illuminate\Http\Request;
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 \Illuminate\Http\Request $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.
Top comments (5)
Nice article. Clearly discussed all about middlleware. Thanks
Thanks
Greate content
Nice article, clear and concise. 🤗
Thanks