spatie/laravel-permission
Manage roles and permissions in Laravel using database-backed models integrated with Laravel’s Gate. Assign roles to users, grant permissions directly or via roles, and authorize actions with the familiar can() checks. Includes docs for setup and usage.
Installation:
composer require spatie/laravel-permission
php artisan migrate
Run migrations to create roles, permissions, and model_has_permissions tables.
Add Trait to User Model:
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
// ...
}
First Use Case: Create a role and assign it to a user:
$role = Role::create(['name' => 'admin']);
$user->assignRole($role);
Check permissions in Blade:
@can('edit articles')
<button>Edit</button>
@endcan
Role-Based Access Control (RBAC):
// Assign role to user
$user->assignRole('editor');
// Check role in controller
if ($user->hasRole('editor')) {
return view('editor.dashboard');
}
Permission-Based Access:
// Grant permission directly
$user->givePermissionTo('publish posts');
// Check permission in middleware
if (!$user->can('publish posts')) {
abort(403);
}
Combined Role + Permission:
// Sync permissions to role
$role = Role::findByName('admin');
$role->syncPermissions(['create users', 'delete posts']);
// Assign role to user
$user->assignRole($role);
Policy Integration:
use Spatie\Permission\PermissionRegistrar;
public function boot()
{
$this->registerPolicies();
$this->registerPermissions();
}
protected function registerPermissions()
{
app(PermissionRegistrar::class)->for('user', [
'edit profile',
'delete account',
]);
}
Scopes for Querying:
// Get users with 'admin' role
$admins = User::role('admin')->get();
// Get users without 'view posts' permission
$nonViewers = User::withoutPermission('view posts')->get();
Artisan for Seed Data:
php artisan permission:create-role admin
php artisan permission:create-permission "manage users" --guard=web
Enum Support (Laravel 8+):
enum PostPermission: string
{
case CREATE = 'create posts';
case EDIT = 'edit posts';
}
// Usage
$user->givePermissionTo(PostPermission::EDIT);
@can(PostPermission::CREATE)
Guard Mismatch:
web, api), ensure permissions/roles are created with the correct guard:
php artisan permission:create-role admin api
guard_name when creating roles/permissions:
$role = Role::create(['name' => 'admin', 'guard_name' => 'api']);
Caching Issues:
php artisan permission:cache-reset
Enum Limitations:
$casts for Permission models (as of v6/v7).enum_value() helper:
$permission = Permission::create(['name' => enum_value(PostPermission::CREATE)]);
Mass Assignment Risks:
guard_name or name to Role/Permission models directly. Use the package’s methods:
// ❌ Avoid:
Role::create(['name' => 'admin', 'guard_name' => 'api']); // May bypass validation
// ✅ Use:
$role = Role::create(['name' => 'admin']);
$role->guard_name = 'api';
$role->save();
Check Guard Names:
$user->getGuardName(); // Should match your auth guard
Permission Hierarchy:
getAllPermissions() to debug inherited permissions:
dd($user->getAllPermissions()->pluck('name'));
Artisan Inspection:
php artisan permission:show web
Middleware Debugging:
public function handle(Request $request, Closure $next)
{
Log::debug('Checking permission: ' . $request->user()->getPermissionNames());
return $next($request);
}
Custom Permission Models:
Spatie\Permission\Models\Permission to add fields (e.g., description):
class CustomPermission extends Permission
{
protected $casts = [
'description' => 'text',
];
}
config/permission.php to use your model:
'models' => [
'permission' => \App\Models\CustomPermission::class,
],
Dynamic Permissions:
use Spatie\Permission\PermissionRegistrar;
$registrar = app(PermissionRegistrar::class);
$registrar->for('post', [
'create',
'read',
'update',
'delete',
]);
Team Support:
config/permission.php:
'enable_team_roles' => true,
$team->assignRole('team-admin');
Policy Integration:
class PostPolicy
{
public function update(User $user, Post $post)
{
return $user->can('edit posts') && $user->id === $post->user_id;
}
}
How can I help you explore Laravel packages today?