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.
composer require spatie/laravel-permission
Publish and run the migrations:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate
Open app/Models/User.php and add the HasRoles trait:
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasFactory, Notifiable, HasRoles;
}
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
$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']);
// Check role
$user->hasRole('admin');
$user->hasAnyRole(['admin', 'editor']);
// Check permission
$user->can('edit posts');
$user->hasPermissionTo('delete users');
// 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 () {
// ...
});
@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
// 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