Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

lara9849's avatar

Middleware parameters

Hello Laracasters,

I was wondering if Middleware support parameters/arguments being passed to them as i would like to integrate one for checking permissions for the system i am working on.

I know that filters did (R.I.P) so was hoping that Middleware, being their successors would have inherited this functionality.

If so, does anyone have an example they could share as i have not been able to dig up much on the topic, thanks.

0 likes
22 replies
bart's avatar

In my opinion this does not work with the new middleware concept currently. But you have access to configs and session, where you are able to store parameters to. Last but not least you have access to the route object, so things like $param = $route->getParameter('param'); should be possible.

Btw there are some discussions about that topic, too and an example about the parameter solution.

http://laravel.io/forum/10-15-2014-laravel-5-passing-parameters-to-middleware-handlers http://www.codeheaps.com/php-programming/laravel-5-middleware-stack-decoded/

An finally the parameter example: http://blog.hernandev.com/en/testing-laravel-5-middlewares

Hope it helps a bit!

3 likes
ATOM-Group's avatar

This is my main gripe with middleware right now. It is "difficult" to make a permission middleware and attach it to a route now. This is the desired functionality that you used to be able to do with filters.

middleware => ['permission:user.ban']

Now the only way to do it is to give the route a name, and reference that route name from the middleware's route object. But this means now my permissions are tightly coupled to my route names, and I don't like this.

2 likes
lara9849's avatar

@tag This is the problem i am facing, i don't want to implement something like this as it seems counter-productive.

I think manual checks of PermissionController@has inside places that require this check is a better solution. At least if a route changes then the system will still function correctly. It's not the best solution but it's more portable than binding routes to permissions which is only going to get in the way in the long run.

mrterryh's avatar

@tag I had the same problem recently, but I came up with a solution. It's not as flexible as being able to specify middleware parameters, but it certainly works.

  1. Have a route like so:

    $router->get('/admin/ban', [ 'uses' => '', 'as' => 'admin.ban', 'middleware' => 'permission' ]);

  2. Create a new config file called route-permissions.php and place in the following:

    return array( 'admin.ban' => 'can_ban_users' );

    The key will be the name of the route, and the value will be the name of the permission.

  3. In your middleware, grab the name of the route and use it to retrieve the config value. Then you can simply check that the authenticated user has the required permission.

    $route = $request->route()->getName(); $permission = Config::get('route-permissions.' . $route);

    if (!Auth::user()->hasPermission($permission)) { return new RedirectResponse(url('/')); }

Works fine for my needs :)

1 like
lara9849's avatar
lara9849
OP
Best Answer
Level 1

Thanks @mrterryh, this is pretty much what i decided upon last night except my permissions live in a table and are not bound to routes.

I am doing this by calling the checks where needed and redirecting with an error as i feel it's the most flexible solution.

if (!Auth::user()->has('role.all')) {
        return redirect('/');
}

or, you can pass multiple roles to check like so...

if (!Auth::user()->has(['role.all', 'account.all'])) {
        return redirect('/');
}
usman's avatar

@bart though using a config file works fine, I still hope Taylor will allow us to pass parameters to the middlewares in the final release.

Cheers :)!

lara9849's avatar

@usman it sure does, just depends on how the permissions will be used in your system. My case is no normal circumstance which is why they live in a database. I also second you on the possibility to pass arguments to middleware as it seems like a case where many people would find use in this type of functionality as it was with filters.

robindfuller's avatar

The solution I have gone with for now is a config file exactly like @mrterryh 's suggestion. Except, for convenience, to compile the config file I have created a console command 'php artisan permission:scan' which scans for custom annotations, using the scans array from the RouteServiceProvider.

So for controller class level permissions I have:

    /**
     * Class PagesController     
     *
     * @Resource("admin/page")
     * @Middleware("auth.admin") 
     * @Permission("can_manage_pages")
     * @package App\Http\Controllers\Admin
     */
    class PageController extends Controller {
    ...

and/or for method level permissions I have:

    /**
     * Display a listing of the resource.
     *
     * @Middleware("auth.admin") // only necessary if not already at class level
     * @Permission("can_view_pages") // merges with possible class level permissions
     * @return Response
     */
    public function index()
    {
        $pages = $this->repo->paginate(20);

        return view('admin.pages.index', compact('pages'));
    }

Originally I scanned the controller directly in the middleware on the fly using the $router->currentRouteAction() to determine which controller to scan, so I didn't even need a config file. However, with all the recent complaints about Route annotations, I felt it would be better (and faster) to compile the config file.

midan888's avatar

Guys this is how you should pass parameters from route to middleware, only way found. Was trying to implement ACL.

In your route do this

Route::get('/user/search', ['middleware' => 'permission', 'section' => 'user.search', 'uses' => 'UserController@search']);

In your middleware class you can do this

public function handle($request, Closure $next) 
{
        $action = $request->route()->getAction();
        // section is your key in route, of course it could have any name
            dump($action['section');
            die();
}
3 likes
ATOM-Group's avatar

@midan888 interesting, so it looks like you can define any arbitrary elements in the array after the URI. 'middleware' and 'uses' are special keys, but that array is not limited to those.

Sounds like a decent work around, even if it is a little more verbose.

Good find.

1 like
JuanjoLainez's avatar

That seems a nice solution if you want to put the permissions in your routes, but I think it will look better and cleaner to put them in the controllers. For me it's easier to read. In Laravel 4 we made it like this:

class UserController extends \BaseController
{
public function __construct()
    {
        $this->beforeFilter('has_permission:read_users', array('only' => array('getSearch', 'show')));
    }
}

where 'has_permissionwas the filter andread_users` the permission. Does anyone knows how to do it this way on Laravel 5?

If routes is the only way, we can not use Route::resource or Route::controller with this solution if each function requires different permissions, right?

davidfaux's avatar

As much as I like using @chrisgeary92's suggestion here I don't want to have the administration faff of maintaining a whole bunch of routes I've decided to try out something a little different, feel free to shoot holes in the solution as it is merely a theory at present, so here goes:

  1. Create a new middleware, let's call it Permit.php
  2. Register your middleware in Kernel.php
  3. In the __construct method of your controller call the middleware as per normal, i.e. $this->middleware('permit');
  4. When and where required set the permission you'd like to enforce as a session variable in the method in question e.g.
public function create()
{
    Session::put('permission', 'user.create');
    //If user does not have this permission linked to his role he will be redirected by this point
    
    return view('users.create');
}

Turns out this is as granular as you need it, each method within your controller can have a different permission if required! Below the middleware I've been using to test theory.

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\RedirectResponse;
use Session;

class Permit {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (Session::has('permission'))
        {
            if( ! \Auth::user()->can(Session::get('permission')))
            {
                flash()->error('Access denied'); //You could set flash messages using Laracasts Flash package as well
                return new RedirectResponse(url('/'));
            }
        }

        return $next($request);
    }

}
chrisgeary92's avatar

Thanks for the alternative method: @dfaux

Correct me if I'm wrong, but this method very similar to the one I suggested (in regards to management of permissions), only you have to manage permission in your controllers where as in my suggestion you would manage them in your routes. Also, you don't have to manage a whole bunch of routes, you can add middleware via the controller __construct() method of your controller. So it would be the same (or less) lines of code than your method. :)

I'm not sure, but if you're writing to the session on every page load, what happens if a user is trigger happy and loads multiple pages at once, do you not run the risk of your session key/value getting overwritten, and users being blocked access to pages they otherwise should have access to? Theoretically, this could happen, although not sure how likely it would be?

Update: Also, (again I don't know for sure), but writing to the session every page loads seems like a waste of server resources. It might be minimal, in which case who really cares ;) but just a thought.

pmall's avatar

@chrisgeary92 Saw this too i think a lot of people will enjoy this. It is like the most frequently asked question on this forum :)

1 like
vladimir's avatar

unfortunately none of links above is not working for me

Please or to participate in this conversation.