Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Role based permission to Laravel

Tags:

php

laravel

I am trying to do a role based permission control in a Laravel application. I want to check what actions can some user do, but i can't figure out how to implement gates and policies in my model (the permission description is in the database and are booleans asociated to a table that stores the resource's ids).

This is the database model that im using:

Diagram

I would like to know if laravel gates is useful in my case, and how can i implement it, if not, how to make a basic middleware that take care of permission control to protect routes (or controllers).

In the table resource i have a uuid that identifies the resources, the alias is the name of the resource and has dot notation values of actions or context of the resource (eg. 'mysystem.users.create', 'mysystem.roles.delete', 'mysystem.users.images.view'). The policy tables has a boolean 'allow' field that describes the permission of users.

Thanks in advance.

like image 562
UselesssCat Avatar asked Dec 14 '17 20:12

UselesssCat


People also ask

How do I add permissions to laravel?

This package allows you to manage user permissions and roles in a database. Once installed you can do stuff like this: // Adding permissions to a user $user->givePermissionTo('edit articles'); // Adding permissions via a role $user->assignRole('writer'); $role->givePermissionTo('edit articles');


1 Answers

This is the way that I implement role based permissions in Laravel using Policies.

Users can have multiple roles. Roles have associated permissions. Each permission allows a specific action on a specific model.

Migrations

Roles table

class CreateRolesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->unique();
            $table->string('label');
            $table->text('description');
            $table->timestamps();
        });
    }
// rest of migration file

Permissions table

class CreatePermissionsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('permissions', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->unique();
            $table->string('label');
            $table->text('description');
            $table->timestamps();
        });
    }
// rest of migration file

Permission Role Pivot Table

class CreatePermissionRolePivotTable  extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('permission_role', function (Blueprint $table) {
            $table->integer('permission_id')->unsigned()->index();
            $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');
            $table->integer('role_id')->unsigned()->index();
            $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
            $table->primary(['permission_id', 'role_id']);
        });
    }
// rest of migration file

Role User Pivot Table

class CreateRoleUserPivotTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('role_user', function (Blueprint $table) {
            $table->integer('role_id')->unsigned()->index();
            $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
            $table->integer('user_id')->unsigned()->index();
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->primary(['role_id', 'user_id']);
        });
    }
// rest of migration file

Models

User

public function roles()
    {
        return $this->belongsToMany(Role::class);
    }

public function assignRole(Role $role)
    {
        return $this->roles()->save($role);
    }

public function hasRole($role)
    {
        if (is_string($role)) {
            return $this->roles->contains('name', $role);
        }
        return !! $role->intersect($this->roles)->count();
    }

Role

class Role extends Model
{
    protected $guarded = ['id'];
    protected $fillable = array('name', 'label', 'description');
    public function permissions()
    {
        return $this->belongsToMany(Permission::class);
    }
    public function givePermissionTo(Permission $permission)
    {
        return $this->permissions()->save($permission);
    }
    /**
     * Determine if the user may perform the given permission.
     *
     * @param  Permission $permission
     * @return boolean
     */
    public function hasPermission(Permission $permission, User $user)
    {
        return $this->hasRole($permission->roles);
    }
    /**
     * Determine if the role has the given permission.
     *
     * @param  mixed $permission
     * @return boolean
     */
    public function inRole($permission)
    {
        if (is_string($permission)) {
            return $this->permissions->contains('name', $permission);
        }
        return !! $permission->intersect($this->permissions)->count();
    }
}

Permission

class Permission extends Model
{
    protected $guarded = ['id'];
    protected $fillable = array('name', 'label', 'description');
    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }
    /**
     * Determine if the permission belongs to the role.
     *
     * @param  mixed $role
     * @return boolean
     */
    public function inRole($role)
    {
        if (is_string($role)) {
            return $this->roles->contains('name', $role);
        }
        return !! $role->intersect($this->roles)->count();
    }
}

Policies

A policy is required for each model. Here is an example policy for a model item. The policy defines the 'rules' for the four actions 'view, create, update, delete.

class ItemPolicy
{
    use HandlesAuthorization;
    /**
     * Determine whether the user can view the item.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function view(User $user)
    {
        $permission = Permission::where('name', 'items-view')->first();
        return $user->hasRole($permission->roles);
    }
    /**
     * Determine whether the user can create items.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function create(User $user)
    {
        $permission = Permission::where('name', 'items-create')->first();
        return $user->hasRole($permission->roles);
    }
    /**
     * Determine whether the user can update the item.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function update(User $user)
    {
        $permission = Permission::where('name', 'items-update')->first();
        return $user->hasRole($permission->roles);
    }
    /**
     * Determine whether the user can delete the item.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function delete(User $user)
    {
        $permission = Permission::where('name', 'items-delete')->first();
        return $user->hasRole($permission->roles);
    }
}

Register each policy in AuthServiceProvider.php

use App\Item;
use App\Policies\ItemPolicy;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        Item::class => ItemPolicy::class,
    ];
// rest of file

Controllers

In each controller, refer to the corresponding authorisation action from the policy.

For example, in the index method of ItemController:

public function index()
{
    $this->authorize('view', Item::class);

    $items = Item::orderBy('name', 'asc')->get();

    return view('items', ['items' => $items]);
}

Views

In your views, you can check if the user has a specific role:

@if (Auth::user()->hasRole('item-administrator'))
// do stuff
@endif

or if a specific permission is required:

@can('create', App\User::class)
// do stuff
@endcan
like image 91
kerrin Avatar answered Oct 23 '22 11:10

kerrin