Laravel 12 Roles and Permissions with Spatie

Laravel 12 Roles and Permissions with Spatie

Laravel 12 Roles and Permissions with Spatie

Managing user access levels is a core requirement of most applications. In this tutorial, you will learn how to implement a complete roles and permissions system in Laravel 12 using the spatie/laravel-permission package.

Step 1: Install the Package

composer require spatie/laravel-permission

Publish and run the migrations:

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

Step 2: Configure the User Model

Open app/Models/User.php and add the HasRoles trait:

use Spatie\Permission\Traits\HasRoles;

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

Step 3: Create Roles and Permissions in a Seeder

php artisan make:seeder RolesAndPermissionsSeeder
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class RolesAndPermissionsSeeder extends Seeder
{
    public function run(): void
    {
        // Reset cached roles and permissions
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

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

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

        // Create roles and assign permissions
        Role::firstOrCreate(['name' => 'viewer'])
            ->syncPermissions(['view posts']);

        Role::firstOrCreate(['name' => 'editor'])
            ->syncPermissions(['view posts', 'create posts', 'edit posts']);

        Role::firstOrCreate(['name' => 'admin'])
            ->syncPermissions(Permission::all());
    }
}
php artisan db:seed --class=RolesAndPermissionsSeeder

Step 4: Assign Roles to Users

$user = User::find(1);

// Assign a role
$user->assignRole('admin');
$user->assignRole(['editor', 'viewer']);

// Remove a role
$user->removeRole('viewer');

// Sync roles (removes all current roles and assigns new ones)
$user->syncRoles(['editor']);

Step 5: Check Roles and Permissions

// Check role
$user->hasRole('admin');
$user->hasAnyRole(['admin', 'editor']);

// Check permission
$user->can('edit posts');
$user->hasPermissionTo('delete users');

Step 6: Protect Routes with Middleware

// Require a specific role
Route::middleware(['role:admin'])->group(function () {
    Route::resource('users', UserController::class);
});

// Require a specific permission
Route::middleware(['permission:edit posts'])->group(function () {
    Route::get('/posts/{post}/edit', [PostController::class, 'edit']);
    Route::put('/posts/{post}', [PostController::class, 'update']);
});

// Role or permission
Route::middleware(['role_or_permission:admin|edit posts'])->group(function () {
    // ...
});

Step 7: Use in Blade Templates

@role('admin')
    <a href="{{ route('users.index') }}">Manage Users</a>
@endrole

@hasanyrole('admin|editor')
    <a href="{{ route('posts.create') }}">New Post</a>
@endhasanyrole

@can('delete posts')
    <form method="POST" action="{{ route('posts.destroy', $post) }}">
        @csrf @method('DELETE')
        <button>Delete</button>
    </form>
@endcan

Step 8: Build a Role Management Interface

// Controller method to assign roles to a user
public function updateRole(Request $request, User $user): RedirectResponse
{
    $request->validate(['role' => 'required|exists:roles,name']);

    $user->syncRoles([$request->role]);

    return back()->with('success', "Role updated for {$user->name}.");
}
All Comments