Skip to main content

Scoped permissions

Sometimes you may need more than just CRUD permissions, or have certain conditions on them. For example, you may not have the permission to update users, but you should be able to update your own profile.

Creating a permission scope

For this example, we will be creating a permission scope where we check if the model is our logged in user:

class WhereIsSelf extends PermissionScope
{
public function check(User $user, ?Model $model): bool
{
return $model && $user->id === $model->id;
}

public function description(): string
{
return __('Only see and update myself');
}
}

Like policies, the first argument in check is the logged in user, and the second argument is the related model. To seed this permission scope:

/** @var PermissionCreator $creator */
$creator = app(PermissionCreator::class);

$creator->create('users only self',
'users',
false,
true,
false,
true,
false,
WhereIsSelf::class
);

As you can see, we use true for view and update. This means the permission will only apply for these resource actions.

Usage

Permission scopes will automatically be used in policies if you use the ExtensivePermissions helpers like:

return $user->canView('users', $model);

If you specifically want to check if the user has a permission scope:

$user->hasPermissionScope(SessionManagement::class, $model)

// OR:

$user->hasPermissionScope(SessionManagement::class)

Scope groups

Scope groups are groups that can be assigned to a ScopedPermission. The best way to explain this, is by example.

Practical example

Let's assume we have a Ticket system, and we have 2 roles: projectmanager and developer. Let's also assume we have 2 mailboxes: support@qlic.nl and info@qlic.nl.

Now, developers may only access tickets from support@qlic.nl, but project managers may read tickets from all inboxes.

We can have the following PermissionScope for this:

class CanReadTickets extends PermissionScope
{
public function check(User $user, ?Model $model): bool
{
return true;
}

public function description(): string
{
return 'Can read tickets';
}
}

Now everyone with this permission can read all tickets. So let's add the inboxes:

public function groups(): array
{
return ['info@qlic.nl', 'support@qlic.nl'];
}

In the interface, a multi-select will now appear where these groups can be assigned to a permission.

Assigning groups

You can assign or revoke a group via PHP:

$role = Role::first();

$role->giveScopeGroup(CanReadTickets::class, ['info@qlic.nl', 'support@qlic.nl']);
$role->revokeScopeGroup(CanReadTickets::class, ['support@qlic.nl']);
caution

It is good practise to give the admin role every scope group by default. You need to do this manually:

$adminRole = Role::where('name', config('permission.super_admin'))->first();
$adminRole->giveScopeGroup(CanReadTickets::class, ...);

Usage

You can check whether a user has a scope group:

$user->hasPermissionScopeGroup(CanReadTickets::class, 'info@qlic.nl');

Configuring the options

You can display more information for each group in the interface by adding the following method:

public function selectOptions(): array
{
return [
[
'label' => 'Support box',
'value' => 'support@qlic.nl',
'description' => 'My description'
],
[
'label' => 'Info box',
'value' => 'info@qlic.nl',
'description' => 'My description'
],
];
}

By default, you can assign multiple groups to a permission, however you can disable this:

public function canHaveMultipleGroups(): bool
{
return false;
}