Passing parameters to Middleware in Laravel 5.1

Posted on June 09, 2015 | By Matt Stauffer


Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

If you remember my blog post about Filter-style middleware in Laravel 5.0, middleware got a big bump in its importance and priority in Laravel 5.0. In early development of 5.0, route filters were actually removed entirely, but later they were brought back—primarily (I assume) because you couldn't pass parameters to middleware, so they couldn't perfectly replace filters.

This is no longer the case. Middleware can now take parameters.

(and there was much rejoicing)

When would I use middleware paremeters?

Remember, middleware is like a decorator that goes around your entire application request. It takes in a request, does some work, and spits out a response. And usually, it does that work consistently across every section of your application.

But what if you want to be able to customize exactly how the middleware is being processed for a given route, without creating a new middleware for every place it's customized?

Let's consider the most common example: Scoping authentication middleware based on roles. You want to, in the route definition, choose how the authentication middleware runs, by passing it a "role" parameter that defines which user role is required in order to access this route.

Using parameterized middleware in the route defintion

When you're adding middleware to a route definition, you'd normally set it like this:

Route::get('company', ['middleware' => 'auth', function () {
    return view('company.admin');
}]);

So, let's add in our parameter to show that the user must have the owner role:

Route::get('company', ['middleware' => 'auth:owner', function () {
    return view('company.admin');
}]);

Note that you can also pass multiple parameters as a comma-separated list:

Route::get('company', ['middleware' => 'auth:owner,view', function () {
    return view('company.admin');
}]);

Creating parameterized middleware

So, how do we update our middleware to teach it to take parameters?

<?php

namespace App\Http\Middleware;

use Closure;

class Authentication
{
    public function handle($request, Closure $next, $role)
    {
        if (auth()->check() && auth()->user()->hasRole($role)) {
            return $next($request);
        }

        return redirect('login');
    }
}

Note that the handle() method, which usually only takes a $request and a $next closure, has a third parameter, which is our middleware parameter. If you passed in multiple parameters to your middleware call in the route definition, just add more parameters to your handle() method:

    public function handle($request, Closure $next, $role, $action)

NOTE: If you've never used middleware before, you need to ensure that this middleware is registered in the HTTP Kernel as a routeMiddleware—there's no way you could pass parameters to a universal middleware.

Conclusissimo

That's it! There's now no reason to use filters at all. I for one welcome our middleware overlords.


Comments? I'm @stauffermatt on Twitter


Tags: laravel  •  laravel 5.1