Ability to forbid permissions #1895
carbontwelve
started this conversation in
Ideas
Replies: 2 comments
-
It sounds very useful, but unfortunately there is no one to develop that functionality, and they probably want to keep it simple, maybe an optional trait |
Beta Was this translation helpful? Give feedback.
0 replies
-
for anyone who needs this, just create <?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Collection;
use Spatie\Permission\Contracts\Permission;
use Spatie\Permission\Exceptions\PermissionDoesNotExist;
use Spatie\Permission\PermissionRegistrar;
trait HasRolesAndForbiddenPermissions{
use \Spatie\Permission\Traits\HasRoles {
hasPermissionTo as protected hasPermissionToTrait;
hasPermissionViaRole as hasPermissionViaRoleTrait;
hasDirectPermission as hasDirectPermissionTrait;
getPermissionsViaRoles as getPermissionsViaRolesTrait;
getAllPermissions as getAllPermissionsTrait;
}
public static function bootHasForbiddenPermissions()
{
static::deleting(function ($model) {
if (method_exists($model, 'isForceDeleting') && ! $model->isForceDeleting()) {
return;
}
$model->forbidden_permissions()->detach();
});
}
private function getPermissionClassKeyName()
{
$class = $this->getPermissionClass();
$model = new $class;
return $model->getKeyName();
}
public function forbidden_permissions(): BelongsToMany
{
$relation = $this->morphToMany(
config('permission.models.permission'),
'model',
config('permission.table_names.model_has_forbidden_permissions'),
config('permission.column_names.model_morph_key'),
PermissionRegistrar::$pivotPermission
);
if (! PermissionRegistrar::$teams) {
return $relation;
}
return $relation->wherePivot(PermissionRegistrar::$teamsKey, getPermissionsTeamId());
}
public function hasPermissionTo($permission, $guardName = null): bool
{
if ($this->hasForbiddenPermission($permission)) {
return false;
}
return $this->hasPermissionToTrait($permission, $guardName);
}
public function hasForbiddenPermission($permission): bool
{
$permissionFound = $this->filterPermission($permission);
return $this->forbidden_permissions->contains($permissionFound->getKeyName(), $permissionFound->getKey());
}
public function forbidPermissionTo(...$permissions)
{
$permissions = $this->collectPermissions($permissions);
$model = $this->getModel();
if ($model->exists) {
$this->forbidden_permissions()->sync($permissions, false);
$model->load('forbidden_permissions');
} else {
$class = \get_class($model);
$class::saved(
function ($object) use ($permissions, $model) {
if ($model->getKey() != $object->getKey()) {
return;
}
$model->forbidden_permissions()->sync($permissions, false);
$model->load('forbidden_permissions');
}
);
}
return $this;
}
public function unforbidPermissionTo($permission)
{
$this->forbidden_permissions()->detach($this->getStoredPermission($permission));
$this->load('forbidden_permissions');
return $this;
}
protected function hasPermissionViaRole(Permission $permission): bool
{
if ($this->hasForbiddenPermission($permission)) {
return false;
}
return $this->hasPermissionViaRoleTrait($permission);
}
public function hasDirectPermission($permission): bool
{
if ($this->hasForbiddenPermission($permission)) {
return false;
}
return $this->hasDirectPermissionTrait($permission);
}
public function getPermissionsViaRoles(): Collection
{
$keyName = $this->getPermissionClassKeyName();
return $this->getPermissionsViaRolesTrait()->whereNotIn($keyName, $this->forbidden_permissions->pluck($keyName)->toArray())->values();
}
public function getAllPermissions(): Collection
{
$keyName = $this->getPermissionClassKeyName();
return $this->getAllPermissionsTrait()->whereNotIn($keyName, $this->forbidden_permissions->pluck($keyName)->toArray())->values();
}
public function syncForbiddenPermissions(...$permissions)
{
$this->forbidden_permissions()->detach();
return $this->forbidForbiddenPermissionTo($permissions);
}
public function getForbiddenPermissionNames(): Collection
{
return $this->forbidden_permissions->pluck('name');
}
} |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Looking through the libraries source code I can see that permissions appear to be additive in that if a user belongs to one or more roles where one of those roles has a permission the user will be considered to have that permission.
For the majority of contexts this is absolutely fine. However it can be useful to be able to do
$user->forbidTo('view widgets')
or$role->forbidTo('view widgets')
where even two out of three roles a user belongs to has permission toview widgets
because one of the roles has it set as forbidden the$user->can('view widgets')
would then returnfalse
.This would be handy in my context where we have some global roles such as: "shipping manager", "stock clerk", "technician", etc which allow particular permissions however we also have roles per external company able to consume our api where we want to add their users as "Company A && technician" but company A is forbidden from viewing widgets and so while the technician role might normally allow it due to the forbid on the company role its not allowed for those users.
Beta Was this translation helpful? Give feedback.
All reactions