Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Permission Laravel Package

spatie/laravel-permission

Database-backed roles and permissions for Laravel. Assign roles and permissions to users, sync them to the Gate, and check abilities with Laravel’s built-in can()/authorize features. Includes migrations, caching, teams, and flexible model setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require spatie/laravel-permission
    

    Run migrations:

    php artisan migrate
    
  2. Publish Config (Optional)

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

    Modify config/permission.php if needed (e.g., disable teams, adjust model names).

  3. Model Setup Use the provided traits in your User model (or any model needing permissions):

    use Spatie\Permission\Traits\HasRoles;
    use Spatie\Permission\Traits\HasPermissions;
    
    class User extends Authenticatable
    {
        use HasRoles, HasPermissions;
    }
    
  4. First Use Case: Assigning Permissions

    // Direct permission assignment
    $user->givePermissionTo('edit_articles');
    
    // Role-based assignment
    $role = Role::create(['name' => 'editor']);
    $role->givePermissionTo('edit_articles');
    $user->assignRole($role);
    
  5. Check Permissions

    if ($user->can('edit_articles')) {
        // Grant access
    }
    

Implementation Patterns

Core Workflows

  1. Permission Management

    • Create Permissions Dynamically:
      Permission::create(['name' => 'delete_posts']);
      
    • Bulk Assignment:
      $user->givePermissionTo(['edit_articles', 'publish_posts']);
      $user->revokePermissionTo('edit_articles');
      
  2. Role-Based Access

    • Hierarchical Roles:
      $adminRole = Role::create(['name' => 'admin']);
      $editorRole = Role::create(['name' => 'editor']);
      $adminRole->givePermissionTo($editorRole->allPermissions); // Inherit permissions
      
    • Role Assignment:
      $user->assignRole('editor');
      $user->removeRole('editor');
      
  3. Policy Integration

    • Use Laravel’s policies with permissions:
      class PostPolicy {
          public function update(User $user, Post $post) {
              return $user->can('edit_articles');
          }
      }
      
  4. Middleware for Routes

    • Protect routes with role or permission middleware:
      Route::get('/dashboard', function () {
          // ...
      })->middleware(['role:admin']);
      
    • Custom middleware:
      public function handle(Request $request, Closure $next) {
          if (!$request->user()->can('manage_users')) {
              abort(403);
          }
          return $next($request);
      }
      
  5. Teams (Optional)

    • Enable in config/permission.php:
      'teams' => [
          'enabled' => true,
      ],
      
    • Assign roles to teams:
      $team = Team::create(['name' => 'Content Team']);
      $team->assignRole('editor');
      
  6. Wildcard Permissions

    • Use wildcards for broad permissions (e.g., manage_*):
      $user->givePermissionTo('manage_*');
      $user->can('manage_posts'); // Returns true
      

Integration Tips

  • Seeding Permissions: Create a seeder to populate initial roles/permissions:

    public function run() {
        $admin = Role::create(['name' => 'admin']);
        $admin->givePermissionTo(Permission::all());
    
        $user = User::find(1);
        $user->assignRole($admin);
    }
    
  • Caching: Cache permissions for performance (enabled by default):

    // Clear cache manually if needed
    $user->syncPermissions([]);
    
  • API Responses: Return user roles/permissions in API responses:

    return response()->json([
        'roles' => $user->roles->pluck('name'),
        'permissions' => $user->permissions->pluck('name'),
    ]);
    
  • Event Listeners: Listen for permission changes:

    public function handle(PermissionAttachedEvent $event) {
        // Log or notify when permissions are added
    }
    

Gotchas and Tips

Pitfalls

  1. Case Sensitivity: Permissions and roles are case-sensitive. Ensure consistency when assigning/checking:

    // Fails if permission is 'edit_articles' but checked as 'Edit_Articles'
    $user->can('edit_articles'); // Correct
    
  2. Model Binding: Ensure your User model (or other models) uses the correct traits (HasRoles, HasPermissions). Forgetting this will cause method errors.

  3. Wildcard Conflicts: Wildcard permissions (e.g., manage_*) can override explicit permissions. Test thoroughly:

    $user->givePermissionTo('manage_posts');
    $user->givePermissionTo('manage_*'); // Overrides explicit 'manage_posts'
    
  4. Teams Feature:

    • Disabling teams in config/permission.php removes all team-related methods (e.g., teams()). Ensure compatibility if using third-party packages that rely on teams.
    • Teams are not a replacement for roles; they are additive. Assign roles to teams, not permissions directly.
  5. Migration Conflicts: If you customize the migration tables (e.g., model_morph_key), ensure the package’s migrations match your schema. Override migrations if needed:

    // In a custom migration
    Schema::create('model_has_permissions', function (Blueprint $table) {
        $table->unsignedBigInteger('permission_id');
        $table->unsignedBigInteger('model_id');
        $table->string('model_type');
        $table->primary(['permission_id', 'model_id', 'model_type']);
    });
    
  6. Permission Caching: Caching can cause stale data if permissions are updated dynamically. Clear cache after bulk updates:

    $user->syncPermissions([]); // Clears cache
    
  7. Laravel Gates vs. Permissions: Gates and permissions are separate but can be combined. Avoid redundancy:

    // Bad: Duplicate logic
    Gate::define('edit_post', function (User $user, Post $post) {
        return $user->can('edit_posts'); // Redundant if using middleware
    });
    

Debugging Tips

  1. Check Database: Verify permissions/roles exist in roles, permissions, and pivot tables:

    SELECT * FROM model_has_roles WHERE model_type = 'App\Models\User';
    
  2. Enable Query Logging: Debug permission checks with Laravel’s query log:

    DB::enableQueryLog();
    $user->can('edit_articles');
    dd(DB::getQueryLog());
    
  3. Middleware Order: Ensure permission middleware runs after auth middleware in app/Http/Kernel.php:

    protected $middleware = [
        // ...
        \App\Http\Middleware\Authenticate::class,
        \Spatie\Permission\Middlewares\RoleOrPermission::class,
    ];
    
  4. Events for Debugging: Listen for events to trace permission changes:

    PermissionAttached::dispatch($user, $permissions);
    

Extension Points

  1. Custom Permission Models: Extend the Permission model for additional fields:

    class CustomPermission extends Permission {
        protected $casts = [
            'is_active' => 'boolean',
        ];
    }
    

    Update config/permission.php:

    'models' => [
        'permission' => CustomPermission::class,
    ],
    
  2. Custom Role Hierarchy: Implement role inheritance logic in a service:

    class RoleService {
        public function getEffectivePermissions(User $user) {
            $permissions = $user->permissions;
            foreach ($user->roles as $role) {
                $permissions = $permissions->merge($role->permissions);
            }
            return $permissions;
        }
    }
    
  3. Dynamic Permissions: Load permissions from external sources (e.g., API) and sync them:

    public function syncExternalPermissions(User $user) {
        $externalPermissions = $this->fetchFromApi($user);
        $user->syncPermissions($externalPermissions);
    }
    
  4. Policy-Based Permissions: Combine policies with permissions for granular control:

    class PostPolicy {
        public function delete(User $user, Post $post) {
            return $user->can('delete_posts') && $post->owner->is($user);
        }
    }
    
  5. Custom Guards: Extend the package’s guard logic for non-standard authentication:

    class CustomGuard extends Guard {
        public function user() {
            // Custom user resolution
        }
    }
    

    Bind the guard in AuthServiceProvider:

    $this
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony