0

I'm designing a web app where there are several user roles and permissions so I try out laravel-permission which looks great and I can create roles and permissions according to the guide.

I created user roles: super-admin, admin, office-admin, inspector, user.
super-admin can grant admin role,
admin can grant office-admin role and
office-admin can grant inspector role.

And I created grant-user permission and UserPolicy which has grant() method that looks like this.

public function grant(User $user, User $model, string $role)
{
    // super-admin can grant admin
    if ($user->isSuperAdmin() && $role === User::ADMIN) {
        return true;
    }

    // admin can grant office-admin
    if ($user->isAdmin() && $role === User::OFFICE_ADMIN) {
        return true;
    }

    // office-admin can grant inspector in the office
    if (
        $user->isOfficeAdmin() && $role === User::INSPECTOR &&
        $user->office->id === $model->office->id
    ) {
        return true;
    }
}

But then I do not use permissions table at all, just roles and UserPolicy. So I think I did something wrong here. What would be the use for permissions table in this case? What should be changed to use it correctly?

1 Answer 1

1

The way you've written the access checks in the method is completely fine. Your question seems to be more about understanding how permissions are supposed to work. I'll explain it below.

In an ideal application, you don't hardcode the roles. Instead, the permissions are hardcoded. Laravel permission package also recommends this as a best practice: https://spatie.be/docs/laravel-permission/v5/best-practices/roles-vs-permissions

So you check for permissions in the code using one of the two ways:

  1. auth()->user()->can('edit answers')
  2. @can('edit answers') - blade directive

Here the permission is edit answers. If your user has direct permission assigned or one of the roles assigned to the user has this permission, the statements above return true.

The entities are connected using this way:

  1. User -> has roles
  2. Role -> has permissions

I'll explain the tables in the laravel-permission package:

  1. model_has_roles - Defines mapping between user and roles.
  2. role_has_permissions - Defines mapping between role and permissiones.
  3. model_has_permissions - Defines direct mapping between user and permissions. I personally avoid this as it becomes difficult to maintain permissions for every user.

So in your policy file, the permission grant-user will be checked like this:

public function grant(User $user, User $model, string $role)
{
    // checks if user has direct permission mapped
    // or any role assigned to the user has permission mapped
    return $user->can('grant-user');
}

The main advantage with this is you can create and delete as many roles as you want and assign them any permissions. No need to update the code if you decide that an office admin cannot grant a user anymore. You just remove the permission mapping from the database.

Sign up to request clarification or add additional context in comments.

2 Comments

thanks! however I still don't understand how to check, for example, that office-admin can grant inspector. where would the check code go to?
Your use case strictly requires the roles to be checked. I believe your implementation is correct in that case. The permissions are supposed to be more generic to determine whether a role can perform an action or not (like grant-user and not like grant-inspector-user).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.