saeedvir / laravel-permissions
A highly optimized role and permission package for Laravel 11/12 with caching, multiple guards, wildcard permissions, super admin, and Laravel Gate integration
Installs: 8
Dependents: 0
Suggesters: 0
Security: 0
Stars: 10
Watchers: 0
Forks: 1
Open Issues: 0
pkg:composer/saeedvir/laravel-permissions
Requires
- php: ^8.2
- illuminate/cache: ^11.0|^12.0
- illuminate/database: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^11.0|^12.0
README
Laravel Permissions Package
A highly optimized role and permission package for Laravel 11/12 with advanced features including multiple guards, wildcard permissions, super admin, expirable permissions, expirable roles, and Laravel Gate integration.
✨ Features
Core Features
- ✅ Role-based Access Control (RBAC)
- ✅ Permission Management
- ✅ Direct User Permissions
- ✅ Polymorphic Relationships - Works with any model
Advanced Features
- 🚀 Multiple Guards Support - Separate permissions for web, api, admin
- 🎯 Wildcard Permissions - Use
posts.*to grant all post permissions - 👑 Super Admin Role - Automatically has ALL permissions
- ⏰ Expirable Permissions - Set expiration dates on permissions
- ⏰ Expirable Roles - Set expiration dates on roles (NEW in v2.1.0)
- 🔗 Laravel Gate Integration - Use
$user->can()natively - 📊 Query Scopes -
User::role('admin')->get() - 🔒 Database Transactions - Atomic permission changes
Performance
- ⚡ Advanced Caching with Redis tags support
- 💾 Memory Optimized with eager loading
- 🚄 Database Optimized with composite indexes
- 📦 Multiple Database Support
Developer Experience
- 🛡️ Middleware Protection for routes
- 🎨 Blade Directives for templates
- 📝 Comprehensive Documentation
- ✅ Laravel 11/12 Compatible
Requirements
- PHP 8.2 or higher
- Laravel 11.x or 12.x
- Composer
Quick Start
# Install package composer require saeedvir/laravel-permissions # Publish config php artisan vendor:publish --tag=permissions-config # Run migrations php artisan migrate # Add trait to User model and start using!
Installation
Step 1: Install via Composer
Install the package via Composer:
composer require saeedvir/laravel-permissions
The package will automatically register its service provider.
Step 2: Publish Configuration
Publish the configuration file:
php artisan vendor:publish --tag=permissions-config
Step 3: Configure Database
Update your .env file:
PERMISSION_DB_CONNECTION=mysql PERMISSION_DB_NAME=laravel_permission PERMISSION_CACHE_ENABLED=true PERMISSION_CACHE_EXPIRATION=3600
Step 4: Configure Database Connection
Update config/permissions.php to set your database connection properly.
Step 5: Run Migrations
php artisan migrate
Or publish and customize migrations first:
php artisan vendor:publish --tag=permissions-migrations php artisan migrate
Setup
Add Trait to User Model
Add the HasRolesAndPermissions trait to your User model:
<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Saeedvir\LaravelPermissions\Traits\HasRolesAndPermissions; class User extends Authenticatable { use HasRolesAndPermissions; // ... rest of your User model }
Usage
Creating Roles and Permissions
use Saeedvir\LaravelPermissions\Models\Role; use Saeedvir\LaravelPermissions\Models\Permission; // Create roles $admin = Role::create([ 'name' => 'Administrator', 'slug' => 'admin', 'description' => 'Administrator role with full access' ]); $editor = Role::create([ 'name' => 'Editor', 'slug' => 'editor', 'description' => 'Editor role' ]); // Create permissions $createPost = Permission::create([ 'name' => 'Create Post', 'slug' => 'create-post', 'description' => 'Can create posts' ]); $editPost = Permission::create([ 'name' => 'Edit Post', 'slug' => 'edit-post', 'description' => 'Can edit posts' ]); $deletePost = Permission::create([ 'name' => 'Delete Post', 'slug' => 'delete-post', 'description' => 'Can delete posts' ]);
Assigning Permissions to Roles
// Give permissions to role $admin->givePermissionTo('create-post', 'edit-post', 'delete-post'); $editor->givePermissionTo('create-post', 'edit-post'); // Or using Permission models $admin->givePermissionTo($createPost, $editPost, $deletePost); // Revoke permission $editor->revokePermissionTo('edit-post'); // Sync permissions (removes old, adds new) $editor->syncPermissions(['create-post']);
Assigning Roles to Users
$user = User::find(1); // Assign role $user->assignRole('admin'); // Assign multiple roles $user->assignRole('admin', 'editor'); // Or using Role models $user->assignRole($admin, $editor); // Assign role with expiration (NEW in v2.1.0) $user->assignRoleUntil('premium', now()->addMonth()); $user->assignRoleUntil('trial-user', now()->addDays(7)); // Remove role $user->removeRole('editor'); // Sync roles (removes old, adds new) $user->syncRoles(['admin']);
Giving Direct Permissions to Users
$user = User::find(1); // Give direct permission to user $user->givePermissionTo('create-post'); // Give multiple permissions $user->givePermissionTo('create-post', 'edit-post'); // Give permission with expiration $user->givePermissionToUntil('create-post', now()->addWeek()); // Revoke permission $user->revokePermissionTo('edit-post'); // Sync permissions $user->syncPermissions(['create-post']);
Checking Roles and Permissions
$user = User::find(1); // Check if user has role (automatically filters expired roles) if ($user->hasRole('admin')) { // User is admin } // Check multiple roles (any) if ($user->hasAnyRole(['admin', 'editor'])) { // User has at least one of these roles } // Check multiple roles (all) if ($user->hasAllRoles(['admin', 'editor'])) { // User has all these roles } // Check permission (includes permissions from active roles, filters expired) if ($user->hasPermission('create-post')) { // User can create posts } // Check multiple permissions (any) if ($user->hasAnyPermission(['create-post', 'edit-post'])) { // User has at least one of these permissions } // Check multiple permissions (all) if ($user->hasAllPermissions(['create-post', 'edit-post'])) { // User has all these permissions } // Get all user permissions (direct + from active roles) $permissions = $user->getAllPermissions();
Using Blade Directives (Optional - needs implementation)
@role('admin') <p>You are an administrator!</p> @endrole @hasrole('admin') <p>You are an administrator!</p> @endhasrole @permission('create-post') <a href="/posts/create">Create Post</a> @endpermission @haspermission('create-post') <a href="/posts/create">Create Post</a> @endhaspermission
Advanced Features
Expirable Roles (NEW in v2.1.0)
Assign roles with expiration dates for temporary access:
Enable Feature
In config/permissions.php or .env:
'expirable_roles' => [ 'enabled' => env('PERMISSION_EXPIRABLE_ROLES_ENABLED', false), ],
Or in .env:
PERMISSION_EXPIRABLE_ROLES_ENABLED=true
Usage Examples
use Carbon\Carbon; // Assign temporary role $user->assignRoleUntil('premium', now()->addMonth()); $user->assignRoleUntil('trial-user', now()->addDays(7)); $user->assignRoleUntil('seasonal-mod', Carbon::parse('2025-12-31')); // Using role ID or model $user->assignRoleUntil(1, now()->addWeeks(2)); $role = Role::where('slug', 'editor')->first(); $user->assignRoleUntil($role, now()->addMonths(6)); // All role checks automatically filter expired roles $user->hasRole('premium'); // Returns false after expiration $user->hasPermission('premium-feature'); // Also checks role expiration // Query scopes also respect expiration User::role('premium')->get(); // Only users with active premium role
How it works:
- Expired roles are automatically filtered from all role checks
- Permissions from expired roles are not granted
- Roles with
nullexpires_at never expire (permanent) - Works seamlessly with caching system
Expirable Permissions
Similar to expirable roles, you can set expiration on direct permissions:
Enable Feature
'expirable_permissions' => [ 'enabled' => env('PERMISSION_EXPIRABLE_ENABLED', false), ],
Usage Examples
// Give temporary permission $user->givePermissionToUntil('create-post', now()->addWeek()); $user->givePermissionToUntil('beta-feature', now()->addDays(30)); // Permission automatically expires $user->hasPermission('create-post'); // Returns false after expiration
Wildcard Permissions
Use wildcards for flexible permission matching:
Enable Feature
'wildcard_permissions' => [ 'enabled' => env('PERMISSION_WILDCARD_ENABLED', false), ],
Usage Examples
// Grant wildcard permission $role->givePermissionTo('posts.*'); // Matches all post permissions $user->hasPermission('posts.create'); // true $user->hasPermission('posts.edit'); // true $user->hasPermission('posts.delete'); // true
Super Admin Role
Designate a role that automatically has all permissions:
Enable Feature
'super_admin' => [ 'enabled' => env('PERMISSION_SUPER_ADMIN_ENABLED', false), 'role_slug' => env('PERMISSION_SUPER_ADMIN_SLUG', 'super-admin'), ],
Usage
// Assign super admin role $user->assignRole('super-admin'); // User now has ALL permissions $user->hasPermission('any-permission'); // Always true // Check if user is super admin if ($user->isSuperAdmin()) { // User has unlimited access }
Query Scopes
Powerful query scopes for filtering users:
// Get users with specific role User::role('admin')->get(); User::role(['admin', 'editor'])->get(); // Get users with specific permission User::permission('create-post')->get(); User::permission(['create-post', 'edit-post'])->get(); // Get users without role User::withoutRole('banned')->get(); // Get users without permission User::withoutPermission('delete-post')->get(); // Combine scopes User::role('editor') ->permission('create-post') ->where('status', 'active') ->get();
Middleware Usage
The package provides three middlewares:
1. CheckAuth Middleware
Checks if user is authenticated:
Route::get('/dashboard', function () { return view('dashboard'); })->middleware('check.auth');
2. CheckRole Middleware
Checks if user has specific role(s):
// Single role Route::get('/admin', function () { return view('admin.dashboard'); })->middleware('role:admin'); // Multiple roles (user needs at least one) Route::get('/admin', function () { return view('admin.dashboard'); })->middleware('role:admin|super-admin'); // In route groups Route::middleware(['role:admin'])->group(function () { Route::get('/users', [UserController::class, 'index']); Route::get('/settings', [SettingController::class, 'index']); });
3. CheckPermission Middleware
Checks if user has specific permission(s):
// Single permission Route::post('/posts', [PostController::class, 'store']) ->middleware('permission:create-post'); // Multiple permissions (user needs at least one) Route::put('/posts/{post}', [PostController::class, 'update']) ->middleware('permission:edit-post|edit-own-post'); // In route groups Route::middleware(['permission:manage-posts'])->group(function () { Route::get('/posts', [PostController::class, 'index']); Route::post('/posts', [PostController::class, 'store']); });
Combining Middlewares
Route::middleware(['check.auth', 'role:admin', 'permission:delete-post']) ->delete('/posts/{post}', [PostController::class, 'destroy']);
Configuration
Cache Settings
Control caching behavior in config/permissions.php:
'cache' => [ 'enabled' => env('PERMISSION_CACHE_ENABLED', true), 'expiration_time' => env('PERMISSION_CACHE_EXPIRATION', 3600), // in seconds 'key_prefix' => 'saeedvir_permissions', 'store' => env('PERMISSION_CACHE_STORE', 'default'), ],
Middleware Responses
Configure unauthorized/unauthenticated responses:
'middleware' => [ 'unauthorized_response' => [ 'type' => 'json', // 'json', 'redirect', 'abort' 'redirect_to' => '/unauthorized', 'abort_code' => 403, 'json_message' => 'Unauthorized access.', ], 'unauthenticated_response' => [ 'type' => 'redirect', // 'json', 'redirect', 'abort' 'redirect_to' => '/login', 'abort_code' => 401, 'json_message' => 'Unauthenticated.', ], ],
Performance Settings
'performance' => [ 'eager_loading' => true, // Enable eager loading for relationships 'chunk_size' => 1000, // Chunk size for batch operations ],
Cache Management
Manual Cache Clearing
use Saeedvir\LaravelPermissions\Services\PermissionCache; $cache = app(PermissionCache::class); // Clear specific user cache $cache->clearUserCache($userId); // Clear specific role cache $cache->clearRoleCache($roleId); // Flush all permission caches $cache->flush();
Automatic Cache Clearing
The package automatically clears relevant caches when:
- Roles are assigned/removed from users
- Permissions are assigned/removed from users or roles
- Roles or permissions are deleted or updated
Database Structure
Tables Created
- roles - Stores role definitions
- permissions - Stores permission definitions
- role_has_permissions - Pivot table for role-permission relationships
- model_has_roles - Polymorphic pivot table for user-role relationships
- model_has_permissions - Polymorphic pivot table for user-permission relationships
Performance Optimization Tips
- Enable Caching: Set
PERMISSION_CACHE_ENABLED=truein.env - Use Eager Loading: The package uses eager loading when checking permissions from roles
- Database Indexing: All tables have proper indexes for fast queries
- Use Slugs: Always use slugs (strings) instead of IDs for better cache utilization
- Chunk Large Operations: Use the configured chunk size for batch operations
Testing
composer test
Security
If you discover any security-related issues, please email saeed.es91@gmail.com instead of using the issue tracker.
License
The MIT License (MIT). Please see License File for more information.
Credits
Support
For support, please open an issue on GitHub or contact saeed.es91@gmail.com