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

Authorization Laravel Package

directorytree/authorization

Native, easy role & permission management for Laravel. Adds migrations and an Authorizable trait to your User model for role/permission checks, optional custom migrations/models, caching, gate registration, middleware, and testing support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require directorytree/authorization
    php artisan migrate
    

    This creates the roles, permissions, and role_user/permission_user/permission_role tables.

  2. Attach Trait: Add Authorizable trait to your User model:

    use DirectoryTree\Authorization\Traits\Authorizable;
    class User extends Authenticatable { use Authorizable; }
    
  3. First Use Case: Grant a permission to a role and assign it to a user:

    // Create a permission
    $permission = \DirectoryTree\Authorization\Permission::create([
        'name' => 'users.create',
        'label' => 'Create Users'
    ]);
    
    // Create a role and assign the permission
    $admin = \DirectoryTree\Authorization\Role::create(['name' => 'admin']);
    $admin->grant($permission);
    
    // Assign role to user
    $user->roles()->save($admin);
    
  4. Check Permissions: Use Laravel’s native can() method:

    if (auth()->user()->can('users.create')) {
        // User has permission
    }
    

Implementation Patterns

Core Workflows

Role-Based Access Control (RBAC)

  1. Define Roles:

    $admin = Role::create(['name' => 'admin', 'label' => 'Administrator']);
    $editor = Role::create(['name' => 'editor', 'label' => 'Editor']);
    
  2. Assign Permissions to Roles:

    $admin->grant(['users.create', 'users.edit', 'users.delete']);
    $editor->grant(['users.create', 'users.edit']);
    
  3. Assign Roles to Users:

    $user->roles()->save($admin);
    $user->roles()->save($editor);
    
  4. Check Roles in Middleware/Views:

    // Middleware (Kernel.php)
    'role' => \DirectoryTree\Authorization\Middleware\RoleMiddleware::class,
    
    // Route
    Route::get('/admin', function () {
        // ...
    })->middleware('role:admin');
    
    // Blade
    @role('admin')
        <div>Admin Content</div>
    @endrole
    

Permission-Based Access Control (PBAC)

  1. Grant Permissions Directly to Users:

    $user->grant(['posts.create', 'posts.edit']);
    
  2. Check Permissions in Controllers:

    public function create(PostRequest $request)
    {
        $this->authorize('posts.create'); // Throws 403 if unauthorized
        // ...
    }
    
  3. Use Middleware for Routes:

    // Kernel.php
    'permission' => \DirectoryTree\Authorization\Middleware\PermissionMiddleware::class,
    
    // Route
    Route::post('/posts', [PostController::class, 'store'])
        ->middleware('permission:posts.create');
    

Hybrid Approach (Roles + Permissions)

Combine both for granular control:

// Assign role + direct permissions
$user->roles()->save($admin);
$user->grant('posts.publish'); // Extra permission beyond role

Integration Tips

Seeding Initial Data

Use Laravel’s DatabaseSeeder to populate roles/permissions:

public function run()
{
    $admin = Role::create(['name' => 'admin']);
    $admin->grant(['users.*', 'posts.*']);

    $user = User::first();
    $user->roles()->save($admin);
}

Dynamic Permission Generation

Generate permissions dynamically (e.g., for CRUD operations):

function generateCrudPermissions($resource)
{
    return [
        "{$resource}.create",
        "{$resource}.read",
        "{$resource}.update",
        "{$resource}.delete",
    ];
}

$admin->grant(generateCrudPermissions('users'));

Caching Strategies

Leverage caching for performance (default: daily expiry):

// Customize cache in AuthServiceProvider
Authorization::cacheExpiresIn(now()->addHours(12));

Testing

Set up PermissionRegistrar in TestCase:

protected function setUp(): void
{
    parent::setUp();
    app(PermissionRegistrar::class)->register();
}

public function test_user_can_create_post()
{
    $user = User::factory()->create();
    $user->grant('posts.create');

    $this->actingAs($user)
         ->post('/posts', ['title' => 'Test'])
         ->assertOk();
}

Gotchas and Tips

Pitfalls

  1. Cache Invalidation:

    • Forgetting to flush the cache after bulk permission changes:
      // Manually clear cache if needed
      cache()->forget(Authorization::cacheKey());
      
    • Fix: Use grant()/revoke() methods (they auto-flush cache).
  2. Permission Naming Conflicts:

    • Overlapping permission names (e.g., users.create vs user.create).
    • Fix: Use consistent naming conventions (e.g., pluralize resources).
  3. Middleware Order:

    • permission middleware must run after auth middleware.
    • Fix: Define middleware groups in Kernel.php:
      protected $middlewareGroups = [
          'web' => [
              \App\Http\Middleware\Authenticate::class,
              \DirectoryTree\Authorization\Middleware\PermissionMiddleware::class,
          ],
      ];
      
  4. Trait Overrides:

    • Extending Authorizable trait may break functionality if not careful.
    • Fix: Use Authorization::useUserModel() to customize models instead.
  5. Gate Registration:

    • Disabling gate registration (Authorization::disableGateRegistration()) breaks can() checks.
    • Fix: Only disable if using custom gates.

Debugging Tips

  1. Check Cached Permissions:

    // Inspect cached permissions
    dd(cache()->get(Authorization::cacheKey()));
    
  2. Log Permission Checks:

    // Override hasPermission in User model
    public function hasPermission($permission)
    {
        \Log::info("Checking permission: {$permission} for user: {$this->id}");
        return parent::hasPermission($permission);
    }
    
  3. Verify Middleware:

    • Use php artisan route:list to check middleware order.
    • Test with dd(request()->user()) in middleware to debug user data.
  4. Database Issues:

    • Run php artisan migrate:fresh if migrations fail.
    • Check foreign key constraints if roles/permissions don’t sync.

Extension Points

  1. Custom Permission Logic: Override hasPermission in your User model:

    public function hasPermission($permission)
    {
        if ($permission === 'super.admin') {
            return $this->id === 1; // Only allow ID 1
        }
        return parent::hasPermission($permission);
    }
    
  2. Custom Storage: Use Authorization::usePermissionModel() to store permissions in a custom table (e.g., Redis):

    Authorization::usePermissionModel(
        \App\Models\RedisPermission::class
    );
    
  3. Event Listeners: Listen for permission changes:

    // app/Providers/EventServiceProvider
    protected $listen = [
        \DirectoryTree\Authorization\Events\PermissionGranted::class =>
            \App\Listeners\LogPermissionChange::class,
    ];
    
  4. API Responses: Return user permissions in API responses:

    return response()->json([
        'user' => auth()->user(),
        'permissions' => auth()->user()->permissions->pluck('name'),
    ]);
    
  5. Bulk Operations: Use syncPermissions for bulk updates (avoids N+1 queries):

    $user->permissions()->sync(['users.create', 'users.edit']);
    

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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4