Laravel Permission Development When to use this skill Use this skill when working with authorization, roles, permissions, access control, middleware guards, or Blade permission directives using spatie/laravel-permission. Core Concepts Users have Roles, Roles have Permissions, Apps check Permissions (not Roles). Direct permissions on users are an anti-pattern; assign permissions to roles instead. Use $user->can('permission-name') for all authorization checks (supports Super Admin via Gate). The HasRoles trait (which includes HasPermissions ) is added to User models. Setup Add the HasRoles trait to your User model: use Spatie \ Permission \ Traits \ HasRoles ; class User extends Authenticatable { use HasRoles ; } Creating Roles and Permissions use Spatie \ Permission \ Models \ Role ; use Spatie \ Permission \ Models \ Permission ; $role = Role :: create ( [ 'name' => 'writer' ] ) ; $permission = Permission :: create ( [ 'name' => 'edit articles' ] ) ; // findOrCreate is idempotent (safe for seeders) $role = Role :: findOrCreate ( 'writer' , 'web' ) ; $permission = Permission :: findOrCreate ( 'edit articles' , 'web' ) ; Assigning Roles and Permissions // Assign roles to users $user -> assignRole ( 'writer' ) ; $user -> assignRole ( 'writer' , 'admin' ) ; $user -> assignRole ( [ 'writer' , 'admin' ] ) ; $user -> syncRoles ( [ 'writer' , 'admin' ] ) ; // replaces all $user -> removeRole ( 'writer' ) ; // Assign permissions to roles (preferred) $role -> givePermissionTo ( 'edit articles' ) ; $role -> givePermissionTo ( [ 'edit articles' , 'delete articles' ] ) ; $role -> syncPermissions ( [ 'edit articles' , 'delete articles' ] ) ; $role -> revokePermissionTo ( 'edit articles' ) ; // Reverse assignment $permission -> assignRole ( 'writer' ) ; $permission -> syncRoles ( [ 'writer' , 'editor' ] ) ; $permission -> removeRole ( 'writer' ) ; Checking Roles and Permissions // Permission checks (preferred - supports Super Admin via Gate) $user -> can ( 'edit articles' ) ; $user -> canAny ( [ 'edit articles' , 'delete articles' ] ) ; // Direct package methods (bypass Gate, no Super Admin support) $user -> hasPermissionTo ( 'edit articles' ) ; $user -> hasAnyPermission ( [ 'edit articles' , 'publish articles' ] ) ; $user -> hasAllPermissions ( [ 'edit articles' , 'publish articles' ] ) ; $user -> hasDirectPermission ( 'edit articles' ) ; // Role checks $user -> hasRole ( 'writer' ) ; $user -> hasAnyRole ( [ 'writer' , 'editor' ] ) ; $user -> hasAllRoles ( [ 'writer' , 'editor' ] ) ; $user -> hasExactRoles ( [ 'writer' , 'editor' ] ) ; // Get assigned roles and permissions $user -> getRoleNames ( ) ; // Collection of role name strings $user -> getPermissionNames ( ) ; // Collection of permission name strings $user -> getDirectPermissions ( ) ; // Direct permissions only $user -> getPermissionsViaRoles ( ) ; // Inherited via roles $user -> getAllPermissions ( ) ; // Both direct and inherited Query Scopes $users = User :: role ( 'writer' ) -> get ( ) ; $users = User :: withoutRole ( 'writer' ) -> get ( ) ; $users = User :: permission ( 'edit articles' ) -> get ( ) ; $users = User :: withoutPermission ( 'edit articles' ) -> get ( ) ; Middleware Register middleware aliases in bootstrap/app.php : -> withMiddleware ( function ( Middleware $middleware ) { $middleware -> alias ( [ 'role' => \ Spatie \ Permission \ Middleware \ RoleMiddleware :: class , 'permission' => \ Spatie \ Permission \ Middleware \ PermissionMiddleware :: class , 'role_or_permission' => \ Spatie \ Permission \ Middleware \ RoleOrPermissionMiddleware :: class , ] ) ; } ) Use in routes (pipe | for OR logic): Route :: middleware ( [ 'permission:edit articles' ] ) -> group ( function ( ) { ... } ) ; Route :: middleware ( [ 'role:manager|writer' ] ) -> group ( function ( ) { ... } ) ; Route :: middleware ( [ 'role_or_permission:manager|edit articles' ] ) -> group ( function ( ) { ... } ) ; // With specific guard Route :: middleware ( [ 'role:manager,api' ] ) -> group ( function ( ) { ... } ) ; For single permissions, Laravel's built-in can middleware also works: Route :: middleware ( [ 'can:edit articles' ] ) -> group ( function ( ) { ... } ) ; Blade Directives Prefer @can (permission-based) over @role (role-based): @can('edit articles') {{-- User can edit articles (supports Super Admin) --}} @endcan @canany(['edit articles', 'delete articles']) {{-- User can do at least one --}} @endcanany @role('admin') {{-- Only use for super-admin type checks --}} @endrole @hasanyrole('writer|admin') {{-- Has writer or admin --}} @endhasanyrole Super Admin Use Gate::before in AppServiceProvider::boot() : use Illuminate \ Support \ Facades \ Gate ; public function boot ( ) : void { Gate :: before ( function ( $user , $ability ) { return $user -> hasRole ( 'Super Admin' ) ? true : null ; } ) ; } This makes $user->can() and @can always return true for Super Admins. Must return null (not false ) to allow normal checks for other users. Policies Use $user->can() inside policy methods to check permissions: class PostPolicy { public function update ( User $user , Post $post ) : bool { if ( $user -> can ( 'edit all posts' ) ) { return true ; } return $user -> can ( 'edit own posts' ) && $user -> id === $post -> user_id ; } } Enums enum RolesEnum : string { case WRITER = 'writer' ; case EDITOR = 'editor' ; } enum PermissionsEnum : string { case EDIT_POSTS = 'edit posts' ; case DELETE_POSTS = 'delete posts' ; } // Creation requires ->value Permission :: findOrCreate ( PermissionsEnum :: EDIT_POSTS -> value , 'web' ) ; // Most methods accept enums directly $user -> assignRole ( RolesEnum :: WRITER ) ; $user -> hasRole ( RolesEnum :: WRITER ) ; $role -> givePermissionTo ( PermissionsEnum :: EDIT_POSTS ) ; $user -> hasPermissionTo ( PermissionsEnum :: EDIT_POSTS ) ; Seeding Always flush the permission cache when seeding: class RolesAndPermissionsSeeder extends Seeder { public function run ( ) : void { // Reset cache app ( ) [ \ Spatie \ Permission \ PermissionRegistrar :: class ] -> forgetCachedPermissions ( ) ; // Create permissions Permission :: findOrCreate ( 'edit articles' , 'web' ) ; Permission :: findOrCreate ( 'delete articles' , 'web' ) ; // Create roles and assign permissions Role :: findOrCreate ( 'writer' , 'web' ) -> givePermissionTo ( [ 'edit articles' ] ) ; Role :: findOrCreate ( 'admin' , 'web' ) -> givePermissionTo ( Permission :: all ( ) ) ; } } Teams (Multi-Tenancy) Enable in config/permission.php before running migrations: 'teams' => true , Set the active team in middleware: setPermissionsTeamId ( $teamId ) ; When switching teams, unset cached relations: $user -> unsetRelation ( 'roles' ) -> unsetRelation ( 'permissions' ) ; Events Enable in config/permission.php : 'events_enabled' => true , Available events: RoleAttachedEvent , RoleDetachedEvent , PermissionAttachedEvent , PermissionDetachedEvent in the Spatie\Permission\Events namespace. Performance Permissions are cached automatically. The cache is flushed when roles/permissions change via package methods. After direct DB operations, flush manually: app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions() For bulk seeding, use Permission::insert() for speed, but flush the cache afterward.
laravel-permission-development
安装
npx skills add https://github.com/spatie/laravel-permission --skill laravel-permission-development