Spatie Laravel Permission

repository·main·Indexed 11 days ago

https://github.com/spatie/laravel-permission

A Laravel package for managing user permissions and roles in a database, integrating with Laravel's native authorization gates. It provides methods for assigning roles and permissions, automatic cache management via the RefreshesPermissionCache trait, and support for custom models and permission check logic.

Tokens
41.5K
Snippets
136
Records
173
Agent score
94%

What's inside Spatie Laravel Permission

  1. Manage user permissions and roles

    main

    The spatie/laravel-permission package allows you to manage user permissions and roles within a database. It integrates directly with Laravel's built-in authorization system (Gates), meaning once permissions are assigned, you can use Laravel's standard can method to check for authorization.

    // Adding permissions to a user
    $user->givePermissionTo('edit articles');
    
    // Adding permissions via a role
    $user->assignRole('writer');
    
    // Adding permissions to a role
    $role->givePermissionTo('edit articles');
    
    // Checking permissions using Laravel's default gate
    $user->can('edit articles');
  2. How to implement a Super-Admin role

    main

    To allow a specific role (e.g., Super-Admin) to bypass all permission checks, use a Gate::before check in your AuthServiceProvider (or AppServiceProvider in Laravel 11). This ensures that any call to can() or @can returns true for users with this role.

    use Illuminate\Support\Facades\Gate;
    
    public function boot()
    {
        // Implicitly grant "Super-Admin" role all permission checks using can()
        Gate::before(function ($user, $ability) {
            if ($user->hasRole('Super-Admin')) {
                return true;
            }
        });
    }
  3. Best Practice: Roles vs Direct Permissions

    main
    While the package allows assigning permissions directly to users, the recommended best practice is to assign permissions to Roles, and then assign those Roles to Users. This makes permission management more scalable and easier to maintain. Only use direct permissions if you have a specific requirement to grant an individual permission to a specific user outside of their role structure.
  4. Core Concepts of Laravel Permission

    main

    The package follows a specific authorization hierarchy:

    • Hierarchy: Users have Roles, Roles have Permissions, and Applications check Permissions (not Roles).
    • Best Practice: Avoid assigning permissions directly to users; instead, assign permissions to roles and assign those roles to users.
    • Authorization: Use $user->can('permission-name') for all authorization checks. This method is preferred because it integrates with Laravel's Gate and supports 'Super Admin' logic.
    • Trait: The HasRoles trait is the primary entry point for user-based authorization.
  5. How multiple guards affect permissions and roles

    main

    In laravel-permission, guards act as namespaces for permissions and roles. This means that a permission named edit-article created for the web guard is distinct from an edit-article permission created for the admin guard.

    If you attempt to check for a permission or role using a guard/name combination that has not been explicitly registered, the package will throw an exception.

    By default, when creating a permission or role without specifying a guard_name, the package uses the first guard defined in your auth.guards configuration array.

    // Create a manager role for users authenticating with the admin guard:
    $role = Role::create(['guard_name' => 'admin', 'name' => 'manager']);
    
    // Define a `publish articles` permission for the admin users belonging to the admin guard
    $permission = Permission::create(['guard_name' => 'admin', 'name' => 'publish articles']);
    
    // Define a *different* `publish articles` permission for the regular users belonging to the web guard
    $permission = Permission::create(['guard_name' => 'web', 'name' => 'publish articles']);
  6. How to structure Roles and Permissions

    main

    To maintain a scalable and flexible authorization system, follow this hierarchical relationship:

    1. Users are assigned Roles (to group people by sets of permissions).
    2. Roles are assigned Permissions (the granular capabilities).
    3. Permissions are the atomic actions (e.g., view document, edit document).

    Key Principles:

    • Avoid direct permissions on Users: Users should inherit permissions via Roles. This makes management easier as you only need to change a Role's permissions to update all associated users.
    • Check Permissions, not Roles: Your application logic (Views, Policies, Controllers) should check for specific permissions rather than checking if a user has a specific role. This decouples your code from your business logic; you can rename or restructure Roles without changing your codebase, as long as the underlying permissions remain the same.
    • Granularity is better: The more detailed your permission names, the easier it is to control access to specific UI elements or API endpoints.
  7. Core concepts of Permissions and Roles

    main

    The package uses two primary abstractions to manage authorization:

    • Permission: A specific ability or capability within your application (e.g., edit articles).
    • Role: A named group of permissions that can be assigned to users or other models (e.g., writer).

    Permissions can be assigned directly to users, or users can be assigned roles which in turn contain permissions.

  8. How to handle Child User Models with permissions

    main

    Because of Eloquent's polymorphic mapping, child models that inherit from a parent User model may struggle to share the same roles/permissions.

    If you want a child model to share the exact same roles and permissions as the parent (effectively treating the child as the parent in the database), you can override the getMorphClass method to return the parent's morph class name (e.g., 'users').

    Warning: This makes the child model lose its independence regarding roles and permissions; it will always use the parent's identity for authorization checks.

    public function getMorphClass()
    {
        return 'users';
    }
  9. How teams permissions work

    main

    Teams permissions allow you to scope roles and permissions to specific organizational units (teams).

    Core Mechanics

    • Global Scope: A role with team_id = null is a global role. It is unique and can be assigned to users across any team.
    • Team Scope: A role with a specific team_id is only valid within that team. Multiple teams can have a role named 'editor' as long as their team_ids differ.
    • The Active Team ID: The package relies on a global team_id (set via setPermissionsTeamId()) to determine which scope to use for assignments (assignRole(), givePermissionTo()) and checks (hasRole(), can()).
    • Relation Management: Because Eloquent caches relations, switching the active team requires manually unsetting the roles and permissions relations on your models to ensure the next access fetches the data for the newly active team.
  10. Database foreign-key relationship support

    main

    The package uses foreign-key relationships with cascading deletes to ensure data integrity.

    • If your engine supports foreign keys: The database will automatically handle cascading deletes.
    • If your engine does NOT support foreign keys: You must manually alter the migration files. However, as long as you manage related records exclusively through the methods provided by this package, the package's internal detaching logic will prevent data integrity issues.
  11. Understand wildcard permission syntax

    main

    Wildcard permission strings consist of one or more parts separated by dots (.).

    Key Rules:

    • The meaning of each part is determined by your application (e.g., {resource}.{action}.{target}).
    • You can use as many parts as needed; there is no limit to the depth of the hierarchy.
    • Crucial: You must explicitly create the permission (e.g., posts.create.*) in the database before you can assign it to a user or check for it.
    $permission = 'posts.create.1';
  12. How default permission checking works

    main

    By default, the package integrates with Laravel's authorization system by registering a Gate::before() method call. This allows the package to intercept calls to can() helpers and model policies to determine if a user has the required permission by checking the permissions stored in your database.

    This default behavior is controlled by the register_permission_check_method configuration key. If this key is set to true (the default), the package handles permission checks automatically via the database.