So just what is Middleware in Laravel 5? As we know, Laravel five actually ships with an implementation of Middleware in the use of setting up an Authentication service like we discussed in our introduction to Laravel 5. Once you start digging into how middleware works in Laravel 5, you’ll find it to be an invaluable resource for gaining a fantastic level of control over your application. By default, Laravel 5 uses middleware to handle things such as maintenance, cookie encryption, session handling, authentication, CSRF protection, and more. By looking at these in the code, we can learn how to create our own middleware for any purpose we might need.
What Is Middleware
Start With The Official Documentation
Of course the best place to learn about what is middleware in Laravel 5 is to simply start with the official documentation first. The documentation is fantastic, and if you run into trouble, you can always check out the free laracast video that covers middleware. In fact there are some additional great resources in the community to learn more about middleware with one being at codeheaps, and finally Matt Stauffer’s excellent explanation.
So Just What Are Middlewares Then?
In Laravel, Middleware is the mechanism to apply any type of filtering you may need to HTTP requests to your application. With your application living on the internet, its a fair bet that almost all of the interaction with it will be via incoming HTTP requests. Therefore it is important to be able to tap into those requests and take action or filter as needed. This new middleware approach to handling that is really intuitive. An easy way to think about middleware is like that of an onion, where each layer is a specific filter so to speak on the HTTP request. This is how Jeffrey Way explains it in his video, and Richard Bagshaws post even features a nice picture of an onion to hammer that point home. So to skip the verbiage and simply answer the question, Laravel Middlware is a means to filter HTTP requests to your application.
What Would I Use Middleware For?
Indeed that is a fine question young traveler. In fact, you have already made use of Laravel middleware as soon as you installed it and tested out the local skeleton application provided. The most obvious use is that of User Authentication. When you install Laravel, the base install provides a way to register to a phantom application and then redirects you to the home page, or dashboard if you will, of the application. If you’re a guest, you can’t reach this sensitive area. All of this is handled via Middleware in a simple, clean, and transparent way. Ultimately, you can use middleware however you want to. The documentation notes using middleware for perhaps setting headers on HTTP responses, or for use with logging requests to your application.
How Does It Work?
When you start with Laravel, you quickly learn to look to the routes.php
file to get a quick overview of an application, and learn about how and where requests can be made to it. When you need to get that same idea or high level view of Middleware in the application, you point yourself right to the included Kernel.php
file which lives right next to the routes.php
file. Let’s have a look, shall we?
App\Http\Kernel.php source
<?php namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel {
/**
* The application's global HTTP middleware stack.
*
* @var array
*/
protected $middleware = [
'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
'Illuminate\Cookie\Middleware\EncryptCookies',
'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
'Illuminate\Session\Middleware\StartSession',
'Illuminate\View\Middleware\ShareErrorsFromSession',
'App\Http\Middleware\VerifyCsrfToken',
];
/**
* The application's route middleware.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
];
}
Excellent. As we can see there are two instances of the middleware, the application middleware represented by protected $middleware
and the route middleware represented by protected $routeMiddleware
. We’ll stay away from the first instance, since Laravel itself is making use of these to do all of the legwork for us in terms of application level platform type stuff. This first middleware is a global instance of middleware, and anything in there will run on every single HTTP request to the application. The route middleware however is easily customized, and this is where we will tinker with a few things.
The Importance Of Kernel.php
It is in the Kernel.php
file where middleware gets registered. This approach is common in Laravel, as almost everything is registered in some way so that the application can make use of it. This gives us a convenient way to refer to application logic using a shorthand notation, i.e., this ‘key’ uses that ‘class’. An example of this is the auth
and App\Http\Middleware\Authenticate
combination listed above. Laravel makes use of this combination in the HomeController.php as shown here.
App\Http\Controllers\HomeController.php source
<?php namespace App\Http\Controllers;
class HomeController extends Controller {
/*
|--------------------------------------------------------------------------
| Home Controller
|--------------------------------------------------------------------------
|
| This controller renders your application's "dashboard" for users that
| are authenticated. Of course, you are free to change or remove the
| controller as you wish. It is just here to get your app started!
|
*/
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard to the user.
*
* @return Response
*/
public function index()
{
return view('home');
}
}
Put your detective cap on and note that $this->middleware('auth');
snippet inside of the constructor. Hmmmm. Now, we just saw that there is an auth
key that references App\Http\Middleware\Authenticate
in the protected $routeMiddleware
of Kernel.php
. That must mean that whatever is in App\Http\Middleware\Authenticate
is going to run on every request where it is attached. In fact, since that method is applied to the constructor, any other method in this controller will have this logic applied to it. This is where you start to fall in love with middleware in Laravel. With one simple and convenient placement of code, you have far reaching effects on the logic of your application. So let’s see what is in that Authenticate file:
App\Http\Middleware\Authenticate.php source
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Authenticate {
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
* @return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('auth/login');
}
}
return $next($request);
}
}
This is where we start to examine that concept of layers of an onion. We can see that the method here is handle
. handle
is the method that is going to, aptly, handle the incoming HTTP request. Inside of this method, some logic is going to happen, and decisions get made on how to handle that request. When we’re done with that, we simply return the request back to the application, and it can be processed from there. It may even end up hitting yet another different middleware and get handled in a different way. Each time the request gets handled, it has passed through one more layer of the onion. In the example here from the default laravel installation, we have a middleware that looks at the incoming HTTP request, determines if the user is authenticated, and if they are not, they get redirected to the login page. Do not be confused by the mention of $auth in this file. This is simply referring to the instance of Guard
that is being typehinted and passed into the constructor. This does not relate to the auth
key in Kernel.php
. In fact, we could name this instance here anything we want and it will work just the same. Need proof? This Authenticate file with a renamed $auth still works.
Still Works
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Authenticate {
/**
* The Guard implementation.
*
* @var Guard
*/
protected $yabadabado;
/**
* Create a new filter instance.
*
* @param Guard $yabadabado
* @return void
*/
public function __construct(Guard $yabadabado)
{
$this->yabadabado = $yabadabado;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->yabadabado->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('auth/login');
}
}
return $next($request);
}
}
Of course you would never do this, we’re just using it for demonstration purposes to investigate how the middleware registration and actual implementation are related. In summary, let’s examine the flow of this instance of middleware.
- Incoming HTTP request is made to the
/home
route. Route::get('home', 'HomeController@index');
directs this to the proper controller.HomeController.php
has this snippet in it’s constructorpublic function __construct() { $this->middleware('auth'); }
Therefore, before any method runs, the middleware will act on this HTTP request first.
- Determine what
$this->middleware('auth');
refers to. - Check
Kernel.php
for this answer.protected $routeMiddleware = [ 'auth' => 'App\Http\Middleware\Authenticate',
shows us that the
auth
key will make use of the middleware located inApp\Http\Middleware\Authenticate
- We know by examining this file above, that if the user is a guest, they will get redirected to the login page. If not, then they must be authenticated, and they are allowed to move forward.
- If the user is authenticated, their HTTP request will now make it to the next method of the HomeController
public function index() { return view('home'); }
and their home page or dashboard will be loaded.
Cool! This now makes perfect sense, so let’s go ahead and create our own implementation of a middleware now!
Create Your Own Middleware
Like most things in Laravel, you can make use of Artisan, the command line utility to create middleware just like you can for controllers, models, and more. Say you have an Admin only section of the application where you only want an Admin to be able to access. That’s a great candidate for a middleware.
1. Create Our Middleware
php artisan make:middleware AdminMiddleware
Middleware created successfully.
<?php namespace App\Http\Middleware;
use Closure;
class AdminMiddleware {
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
return $next($request);
}
}
This gives us a nice starting point to create our own Middleware. Let’s add our logic to it to protect our administrator area.
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class AdminMiddleware
{
protected $auth;
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
// if they are a guest, go to home page
return \Redirect::to('/');
} elseif ($this->auth->user()->name != 'Admin') {
// if they are logged in and the user is not Admin, go to home page
return \Redirect::to('/');
}
return $next($request);
}
}
In this example, we simply create our own implementation of an authentication type filter that we can use on something like a dedicated AdminController which would handle only the back end of a web application. In this middleware, we make a simple check to see if the user is logged in, and also make sure that they are in fact the Admin. If both of those check out, we let them into the Administrator area of the site.
2. Register Our Middleware
We want to identify our newly created middleware as simply isadmin
, so we’ll add it to our Kernel.php
just like so:
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'isadmin' => 'App\Http\Middleware\AdminMiddleware',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
];
Note that we added 'isadmin' => 'App\Http\Middleware\AdminMiddleware'
to our route middleware array.
3. Apply Our New Middlware To The Administrator Area
App\Http\Controllers\AdminController.php source
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class AdminController extends Controller
{
public function __construct()
{
$this->middleware('isadmin');
}
public function index()
{
return view('admin.index');
}
}
Now, unless a user is the Admin, they will not be able to reach the Administrator area of the application.
In Summary
- As of Laravel 5, Middleware Files live in
app\Http\Middleware
- To quickly see what middleware is registered and in use in your application check the
Kernel.php
file located inapp\Http
- To create your own middleware, make use of
php artisan make:middleware
YourMiddleware - To register your middleware for routes, register in
$routeMiddleware
- To register your middleware globally, register in
$middleware
- To attach a middleware to your entire controller, specify the middleware in your constructor.
- To use middleware on a specific route only, specify it in the route options array in your
routes.php
file.
That’s it for now, happy HTTP filtering!