Laravel User Permissions Beginner Guide

Laravel spatie/laravel-permission package allows you to manage user permissions and roles in a database

1 Installation

1.1 installing the package via composer:

composer require spatie/laravel-permission

1.2 Registering Service Provider

The service provider will automatically get registered. Or you may manually add the service provider in your config/app.php file:

'providers' => [
    // ...
    Spatie\Permission\PermissionServiceProvider::class,
];

1.3 Publish

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

Note : 2 files are created after running the above command

  1. config/permission.php
  2. database/migrations/2023_05_04_063758_create_permission_tables.php

1.4 Clear Config Cache

php artisan config:clear

1.5 Run migrations

php artisan migrate

Check created tables in Database

sqlite> SELECT name FROM sqlite_master WHERE type='table';
+------------------------+
| name                   |
+------------------------+
| migrations             |
| sqlite_sequence        |
| users                  |
| password_resets        |
| failed_jobs            |
| personal_access_tokens |
| permissions            |
| roles                  |
| model_has_permissions  |
| model_has_roles        |
| role_has_permissions   |
+------------------------+
11 rows in set (0.01 sec)

Note: Tables names are defined in config/permission.php

  1. roles
  2. permissions
  3. model_has_permissions
  4. model_has_roles
  5. role_has_permissions

2 Basic Usage

2.1 Update the User Model

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
    use HasRoles;

2.2 Role and Permission Models

A Role and a Permission are regular Eloquent models. They require a name

Roles

Create user roles manually

use Spatie\Permission\Models\Role;
$admin_role = Role::create(['name' => 'admin']);
$guest_role = Role::create(['name' => 'guest']);

Check roles tables

sqlite> SELECT id,name FROM roles;
+----+-------+
| id | name  |
+----+-------+
| 1  | admin |
| 2  | guest |
+----+-------+

Permissions

Create Permissions manually

use Spatie\Permission\Models\Permission;
Permission::create(['name' => 'create post']);
Permission::create(['name' => 'edit post']);
Permission::create(['name' => 'delete post']);
Permission::create(['name' => 'view post']);
sqlite> SELECT id,name FROM permissions;
+----+-------------+
| id | name        |
+----+-------------+
| 1  | create post |
| 3  | delete post |
| 2  | edit post   |
| 4  | view post   |
+----+-------------+

2.3 Create a new users with Admin, guest role

use App\Models\User;
//Admin user
$user = User::create([
'name' => 'abhi',
'email' => 'abhi@test.com',
'password' => bcrypt('123456')
]);

//Admin Role - ID 1
$adminRoleId = 1;
$user->assignRole([$adminRoleId]);

//Guest User
$user = User::create([
'name' => 'benn',
'email' => 'benn@test.com',
'password' => bcrypt('123456')
]);

$roleId = 2; //Guest Role
$user->assignRole([$roleId]);

`

Get Roles

$user = User::find(1);
$roles = $user->getRoleNames(); // Returns a collection
dump($roles); exit();
#items: array:1 [▼
    0 => "admin"
  ]

3 Check User Role

3.1 Snippet

Route::get('/create-post', function () {
    $user = User::find(2);

    if($user->hasRole('admin')){
        return "CREAT POST";
    }else{
        return "INVALID";
    }
});

Check multiple permissions

// or at least one role from an array of roles:
$user->hasRole(['editor', 'moderator']);

3.2 Role - Permissions

Created Permissions

sqlite> SELECT id,name FROM roles;
+----+-------+
| id | name  |
+----+-------+
| 1  | admin |
| 2  | guest |
+----+-------+

sqlite> SELECT id,name FROM permissions;
+----+-------------+
| id | name        |
+----+-------------+
| 1  | create post |
| 3  | delete post |
| 2  | edit post   |
| 4  | view post   |
+----+-------------+

3.3 Assign permissions to Roles

Assign view post to guest role

$role->givePermissionTo($permission);
$role = Role::find(2); //guest
$permission = Permission::find(4); //view post

// A permission can be assigned to a role using either of these methods:

$role->givePermissionTo($permission);
OR
$permission->assignRole($role);


sqlite> SELECT * FROM role_has_permissions;
+---------------+---------+
| permission_id | role_id |
+---------------+---------+
| 4             | 2       |
+---------------+---------+

Multiple permissions can be synced to a role using either of these methods

$role = Role::find(1); //admin
$permissions = Permission::whereIn('name',['create post','edit post'])->get();
$role->syncPermissions($permissions);


sqlite> SELECT * FROM role_has_permissions;
+---------------+---------+
| permission_id | role_id |
+---------------+---------+
| 4             | 2       |
| 1             | 1       |
| 2             | 1       |
+---------------+---------+
3 rows in set (0.00 sec)

3.4 Get User Roles and Permissions

$user = User::find(1);
$permissions = $user->getPermissionsViaRoles();
dump($permissions); exit();
 
 

4 Direct Permissions

4.1 Assing Permission to User

$user = User::find(2);
$user->givePermissionTo('create post');
$user->givePermissionTo(['create post', 'edit post']);

DB Check
sqlite> SELECT * FROM model_has_permissions;
+---------------+-----------------+----------+
| permission_id | model_type      | model_id |
+---------------+-----------------+----------+
| 1             | App\Models\User | 2        |
| 2             | App\Models\User | 2        |
+---------------+-----------------+----------+

4.2 Listing All provided permissions

$user = Auth::user();
#$permissions = $user->getDirectPermissions();
$permissionNames = $user->getPermissionNames();

dump($permissionNames); exit();

Illuminate\Support\Collection {#346 ▼
  #items: array:2 [▼
    0 => "create post"
    1 => "edit post"
  ]

5 Protecting Routes

5.1 Default Middle ware

For checking against a single permission (see Best Practices) using can, you can use the built-in Laravel middleware provided by \Illuminate\Auth\Middleware\Authorize::class like this:

Route::group(['middleware' => ['can:create post']], function () {
    Route::get('/create-new-post', function () {
        return "Success";
    });
});

Route::group(['middleware' => ['can:delete post']], function () {
    Route::get('/delete-post', function () {
        return "Success";
    });
});



Test
http://127.0.0.1:8000/create-new-post
Logged User ID : 2
Output : Success


http://127.0.0.1:8000/delete-post
Logged User ID : 2
Output : 403 THIS ACTION IS UNAUTHORIZED

5.2 Package Middleware

This package comes with RoleMiddleware, PermissionMiddleware and RoleOrPermissionMiddleware middleware. You can add them inside your app/Http/Kernel.php file.

// Laravel 9 uses $routeMiddleware = [
//protected $routeMiddleware = [
// Laravel 10+ uses $middlewareAliases = [
protected $middlewareAliases = [
    // ...
    'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
    'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
    'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
];

5.3 Middleware via Routes

Then you can protect your routes using middleware rules:

Route::group(['middleware' => ['role:admin']], function () {
    //
});

Route::group(['middleware' => ['permission:create post']], function () {
    //
});

Route::group(['middleware' => ['role:admin','permission:create post']], function () {
    //
});

Route::group(['middleware' => ['role_or_permission:create post']], function () {
    //
});

You can specify multiple roles or permissions with a | (pipe) character, which is treated as OR:

Route::group(['middleware' => ['role:admin|guest']], function () {
    //
});

Route::group(['middleware' => ['permission:create post|edit post']], function () {
    //
});

Route::group(['middleware' => ['role_or_permission:admin|edit post']], function () {
    //
});

5.4 Middleware with Controllers

You can protect your controllers similarly, by setting desired middleware in the constructor:

public function __construct()
{
    $this->middleware(['role:admin','permission:create post|edit post']);
}

public function __construct()
{
    $this->middleware(['role_or_permission:admin|create post']);
}

6 Blade Directives

6.1 permission

@can directive to check if a user has a certain permission You can use @can, @cannot, @canany, and @guest to test for permission-related access

@can('create post')
  //
@endcan

OR

@if(auth()->user()->can('create post') && $some_other_condition)
  //
@endif

6.2 Roles

@role('admin')
    Admin 
@else
    Guest
@endrole
@hasexactroles('admin|guest')
    //
@else
    //
@endhasexactroles
Post a Comment (0)
Previous Post Next Post