vpower's avatar

Middleware Multiparams (bug?)

Hi,

I might have discovered a bug in laravel. I want to verify that's the and make sure i'm not making any errors:

Route::get('/', ['uses' =>'HomeController@index', 'middleware' => ['permission:office,other', 'role:admin']]);

The middleware for permission should receive a array with "office" and "other" as laravel.com quotes:

Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a :. Multiple parameters should be delimited by commas.

In my case it doesn't return a array. It returns only the first param "office".

Can anyone verify this is a bug and not a coding error so i can report this?

Thanks.

V

0 likes
12 replies
jimmck's avatar

@vpower Its a documentation issue. The examples are very unclear as to how its works. I took a quick look at the code. But I dont use it so. But the key before the colon should be the same one you use to register the middleware. The values after that are what get passed? Entry corresponds to a variable passed after the Closure field. You have to step through all the indirection of how the Middleware gets loaded to see how those extra parameters get accessed.

d3xt3r's avatar

The documentation is very clear. It clearly says

Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a :. Multiple parameters should be delimited by commas.

It nowhere mentions that you can pass an array as parameter's value. If you need an array, pass the values as pipe delimited or any other delimiter of your choice (except comma) and explode it in the middleware to retrieve an array.

'middleware' => ['permission:office,other'

does not mean that an array will be passed, it simply means if there are multiple parameters values will be assigned to them.

jimmck's avatar

@d3xt3r Great so a share great example of how to use it for us poor mortal beings. Its very uunclear what you do with a bunch of 'hard coded' values in a parameter list.

d3xt3r's avatar

@jimmck

Didn't want to write a lengthy reply, but you left me no choice :( Definitely, i need not to explain what middlewares are for :)

Use case 1: Different guards protecting different part of your application. Suppose, you have a guard set for admin, and want to protect a controller. Then something like.

class AdminController extends Controller
{
    protected $guard = 'admin';

    public function __construct()
    {
        $this->middleware('auth:'.$guard); 
    // or simply 
    $this->middleware('auth:admin');
    }
}

Now the question comes why middleware parameters, and not a different middleware altogether, something like ...

$this->middleware('admin');

OK, but against DRY, if you are just checking against the same logic in different middleware.

Use case 2: Controllers guarded by role => People with different role can access different parts of application.

class PostModerationController extends Controller
{
    public function __construct()
    {
    // A person with admin or moderator role can access this controller
        $this->middleware('role:admin|moderator'); 
    }
}

// In   middleware
public function handle($request, $next, $roles)  {
    
    // Explode the delimited string to get the roles array
    $roles = explode('|',$roles);
}

Case 3: Role and or permission

class PostModerationController extends Controller
{
    public function __construct()
    {
    // A person with admin or moderator role can access this controller
        $this->middleware('access:admin|moderator,can_create_post|can_delete_post'); 
    }
}

// In  `access` middleware
public function handle($request, $next, $roles, $permissions)  {
    
    // Explode the delimited string to get the roles array
    $roles = explode('|',$roles);

    // Explode the delimited string to get the permissions array
    $permissions = explode('|',$permissions);
}

vpower's avatar
vpower
OP
Best Answer
Level 1

Hi @jimmck

Thanks for your response.

I have found several cases where they use this examples. See further in my application. The middleware is applied correctly. In the array in Kernel.php the is permission. Everything is working correctly except the parameter passing.

@d3xt3r funny thing is it think it should. Take a look at: https://ahesanalisuthar.wordpress.com/2015/06/04/laravel-5-1-pass-middleware-parameters-as-array/

When i change the comma for a dash, the string is received correctly. Now only one out of two params are received. It might be a version difference where it's simply changed. But i want to make sure before i start implementing a different solution.

Why else do they point out to use the comma?

@jimmck i chose for the hard coded values to identify that part of the application in my middlewares. Depending on role or permissions. That way i can redirect them before entering the application in case they are not authorized.

Snapey's avatar

@d3xt3r

so, yes then, the documentation is misleading "multiple parameters separated by commas"?

You have had to pipe the parameters, where the op is expecting like role:admin,moderator based on the docs.

Is the alternative (and perhaps the intention behind the docs) is that the middleware has to accept an unknown number of arguments

d3xt3r's avatar

@Snapey It says parameters not multiple values to same parameter.

But yes, its a minute detail which can easily be missed.

d3xt3r's avatar

Yes vargs is a way to go but with its own limitations ....

Snapey's avatar

@d3xt3r or handle($request, $next, permission1, permission2=null, permission3=null)

but then you have to second guess how many permissions you might need to apply

1 like
d3xt3r's avatar

Ya, thats why i prefer passing a pipe delimited value and break it down in the middleware, if i need to pass as array, for two reasons ...

  1. Can pass as many values as needed.
  2. Does not interfere with laravel's internal working, where comma is reserved for parameters.

If you look at my reply, the case 3 is the most generic use case.

lucaplus's avatar

Very old post but I just spent half an hour on this. It looks like the multiple comma separated values are exploded as single parameters after the Closure $next. You can catch them all into a single array variable using ...$requiredRoles.

    public function handle($request, Closure $next, ...$requiredRoles)
    {
    // $requiredRoles is an array containing all the comma separated values

Please or to participate in this conversation.