Laravel-permission: Middleware multiple roles

Created on 30 Aug 2016  路  10Comments  路  Source: spatie/laravel-permission

Is it possible to use multiple roles in middleware?

eg. I have 3 roles setup.
Task User
Task Owner
Task Manager

The user can view
The owner can update their own
The manager can update anyones

So on the form view route I need to check they have any of these roles.
On the form update view I need to make sure they have Owner or Manager roles.

This is what I have so far. I've made the permission optional.

Route::group(['prefix' => 'task', 'middleware' => ['role:Task User']], function() {
...

But then I have to make a Task Manager also a Task User to view the tasks.

I think I know why this doesn't work. But can't figure out the "or" part.

Route::group(['prefix' => 'task', 'middleware' => ['role:Task User','role:Task Owner','role:Task Manager']], function() {
...
    public function handle($request, Closure $next, $role, $permission = null)
    {

        if (Auth::guest()) {
            return redirect('/');
        }

        if (! $request->user()->hasAnyRole($role))
        {
              abort(403);
        }        


        if ($permission != null && ! $request->user()->can($permission)) {
            abort(403);
        }


        return $next($request);
    }

Most helpful comment

I found a way to do this if anyone is still looking:

class RoleMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next, $role = null, $permission = null)
    {
        if (Auth::guest()) {
            return redirect()->route('welcome');
        }

        if($role != null) {
            if (!$request->user()->hasAnyRole(explode("|", $role))) {
                abort(403);
            }
        }
        if($permission != null) {
            if (! $request->user()->can($permission)) {
                abort(403);
            }
        }

        return $next($request);
    }
}

Then, in the middleware, you can make it be:

Route::group(['middleware' => ['role:Admin|Developer']); and it works!

All 10 comments

Did you try it like this:

Route::group(['prefix' => 'task', 'middleware' => ['role:Task User,Task Owner,Task Manager']], function() {

I did, but because the RoleMiddleware handle function expects $role, $permission it wouldn't be right.

Also if I do a dump/dd of the $role within the function I only see the first role passed. So I'm guessing that even if I use several middlware role: statements that it would fail on the first one that returned false. I think I somehow need to pass an array of roles to the middleware. But suspect there's something parsing the middleware before it gets called.

No, true, I think you are right and this is not possible. I do think it might be a valuable concept, so maybe you can send in a pull request, @freekmurze ?

Would it be more easy to have permissions view and edit and check the roles at the Gate?
It always feels kinda dirty to check which role a user has.

That does make sense. But this would still require a PR, correct? I think I deleted the part from the middleware, that requires a role to pass, so that I can just check for permissions. Or is this already possible out of the box? I might have messed that up.

However I agree that the permission solution seems more appropriate.

I could go the permission only route. But I'd have to name each permission carefully and then probably just have one Role.
eg.
RoleTask View
RoleTask Update Own
RoleTask Update Any

Not impossible. A bit of a mod to the RoleMiddleware to remove the need for role/overwrite it with "Role".

In fact it's started me thinking a bit differently about the whole thing :D

This seems to work for the case I'm looking for so far.

Update the Roles and Permissions
Role: Task <- the root Role
Permission: Read, Update, Manage

Role: Task Reader
Permission: Read

Role: Task Owner
Permission: Read, Update

Role: Task Manager
Permission: Read, Update, Manage

Then I give the root role "Task" all of the permissions associated with Task and in the route use role:Task,[permission] to determine if a user can/can't access it. So I think the key for me was just creating the root role.

Then I use @can instead of @hasrole in the blades.

See #120 for how I handled it in one situation I ran into.

I've been blazing away at this and after some rethinking realised that role checking wasn't what I was after :D I originally imagined Roles and Permissions like a tree structure, when actually it's a much more fluid setup. Roles are simply a collection of Permissions. Because Permissions can exists in many Roles there seemed little point in checking the Role and the Permission.

My middleware doesn't even bother with Role checking anymore. A simple can('Task Read') or can('Task Edit') is all that's needed to control routes and blades.

I've now almost setup a user/role/permissions admin panel so they can be edited in a a web ui. I originally looked at backpack, but it was too complete to be an include it what I wanted.

Quite pleased with it so far.
Image
Image
Image

I found a way to do this if anyone is still looking:

class RoleMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next, $role = null, $permission = null)
    {
        if (Auth::guest()) {
            return redirect()->route('welcome');
        }

        if($role != null) {
            if (!$request->user()->hasAnyRole(explode("|", $role))) {
                abort(403);
            }
        }
        if($permission != null) {
            if (! $request->user()->can($permission)) {
                abort(403);
            }
        }

        return $next($request);
    }
}

Then, in the middleware, you can make it be:

Route::group(['middleware' => ['role:Admin|Developer']); and it works!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

devingray picture devingray  路  3Comments

Dreambox13 picture Dreambox13  路  3Comments

neoreids picture neoreids  路  3Comments

enghelewa picture enghelewa  路  4Comments

NattananWs picture NattananWs  路  3Comments