Laravel Roles & Permissions Tutorial Using Spatie Package

 223
Laravel Roles & Permissions Tutorial Using Spatie Package

Overview

Managing user roles and permissions is an essential part of most web applications.

You will learn step-by-step how to integrate the Spatie Laravel Permission package to handle role-based access control.

Step 1: Install the Package
Run the following command to install Spatie's permission package:

composer require spatie/laravel-permission

Run For Laravel 10/11:

Add middleware aliases inside app/Http/Kernel.php

protected $routeMiddleware = [
   // other middleware...
   'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
   'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
   'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
]; 

Run For Laravel 12
In Laravel 12 you need to add permission in bootstrap/app.php file.


use Spatie\Permission\Middleware\RoleMiddleware;
use Spatie\Permission\Middleware\PermissionMiddleware;
use Spatie\Permission\Middleware\RoleOrPermissionMiddleware;
use Illuminate\Foundation\Configuration\Middleware;

->withMiddleware(function (Middleware $middleware): void {
$middleware->alias([
 	'role' => RoleMiddleware::class,
 	'permission' => PermissionMiddleware::class,
 	'role_or_permission' => RoleOrPermissionMiddleware::class,
	]);
})


Step 2: Publish Configuration & Migrations
Now, publish the package’s configuration and migration files:

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
  • This will create two below files:
    • Config -> config/permission.php
    • Migration -> database/migrations/*_create_permission_tables.php

Run the migrations to generate all required database tables:

php artisan migrate
  • The following tables will be created:
    • roles
    • permissions
    • model_has_roles
    • model_has_permissions
    • role_has_permissions
       

Step 3: Add the HasRoles Trait to Your User Model
Open app/Models/User.php and add the HasRoles trait:

use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
   	use HasRoles; //Add HasRoles

	//Other model code....
}

This trait gives your User model access to all role and permission methods — such as assignRole(), hasRole(), givePermissionTo(), and can().

Step 4: Create a Seeder for Roles & Permissions

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class RolesPermissionsSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        // Reset cached roles and permissions
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        // Create permissions
        $permissions = [
            'view users',
            'create users',
            'edit users',
            'delete users',

            'view posts',
            'create posts',
            'edit posts',
            'delete posts',
        ];

        foreach ($permissions as $permission) {
            Permission::firstOrCreate(['name' => $permission]);
        }

        // Create roles
        $role_admin = Role::firstOrCreate(['name' => 'admin']);
        $role_editor = Role::firstOrCreate(['name' => 'editor']);
        $role_user = Role::firstOrCreate(['name' => 'user']);

        // Assign permissions to roles
        $role_admin->givePermissionTo(Permission::all());

        $role_editor->givePermissionTo([
            'view posts',
            'create posts',
            'edit posts'
        ]);

        $role_user->givePermissionTo([
            'view posts'
        ]);
    }
}


Add your seeder inside DatabaseSeeder.php:

public function run(): void
    {
        //User::factory(10)->create();

        $this->call([
            RolesPermissionsSeeder::class,
        ]);
    }


Assign Run Seeder with the following command:

php artisan db:seed

Assign role to a User

Route::get('role-assign', function () {
    $roles = [
        1 => 'admin',
        2 => 'author',
        3 => 'user',
    ];

    foreach ($roles as $userId => $role) {
        if ($user = User::find($userId)) {
            $user->assignRole($role);
        }
    }
    return "Roles assigned successfully!";
});

Step 5: Check Permissions in Blade or Components
You can easily check roles or permissions directly in your views or Livewire components.

Inside the Livewire component:

public $user;
public $role;
public function mount()
{
   $this->user = auth()->user();
   if ($this->user && $this->user->hasRole('author')) {
       $this->role = 'Author';
   } else {
       $this->role = 'User';
   }
}

Inside your Blade view (post-list.blade.php):

@if ($user->can('create_post'))
 <a class="btn btn-primary" href="{{ route('post.create') }}">Add Post</a>
@endif

Step 6: Protect Routes Using Middleware
You can restrict access to certain routes based on user roles or permissions.

Route::get('/posts/create', Post::class)->name('post.create')->middleware('role:author');

Step 7: Clear Caches (important)
Whenever you make role or permission changes, clear your caches:

php artisan optimize:clear
php artisan permission:cache-reset

🎉 You’re Done!

You’ve successfully set up Role-Based Access Control in Laravel using the Spatie Permission package.