A comprehensive and flexible Laravel package for advanced permission management. This package provides a robust system for managing roles, permissions, groups, and entity-specific abilities.
Core Functionality:
-
Role-Based Access Control (RBAC): Define custom roles with specific permission sets. Roles can be assigned to users to manage access levels efficiently.
-
Permission System: Implement fine-grained permissions using a code-based system (e.g.,
posts.create,users.edit). Permissions are global entities that can be assigned to roles and groups. Supports wildcard permissions for flexible access patterns. -
Group Management: Organize users into groups. Groups can have their own permission sets, allowing for efficient permission management when multiple users need the same access level.
-
Entity-Specific Abilities: Grant or deny permissions for specific model instances (e.g., allowing a user to edit a particular post but not others). This provides the most granular level of access control.
-
Caching & Performance: Intelligent caching system to optimize permission checks, reducing database queries and improving application performance.
-
Audit Logging: Optional comprehensive audit trail that logs all permission-related actions including role assignments and permission changes.
-
Laravel Integration: Seamlessly integrates with Laravel's built-in authorization system, including Policies, Blade directives, and middleware for route protection.
- âś… Roles & Permissions: Flexible role system with granular permissions
- âś… Groups: Organize users into groups with shared permissions
- âś… Abilities: Entity-specific permissions for individual models
- âś… Smart Caching: Caching system to optimize permission checks
- âś… Audit Logging: Complete action logging (optional)
- âś… Blade Directives: Blade directives for permission checks in views
- âś… Policies: Integration with Laravel's Policy system
- âś… Middleware: Middleware for route protection
- âś… Artisan Commands: CLI tools for management
- âś… Events: Event system for permission changes (RoleAssigned, RoleRemoved, AbilityGranted, AbilityRevoked)
- âś… Validation: Automatic validation of permission codes
- âś… Performance: Optimized queries with eager loading
- PHP >= 8.1
- Laravel 8.x, 9.x, 10.x, 11.x or 12.x
composer require squareetlabs/laravel-simple-permissionsphp artisan vendor:publish --provider="Squareetlabs\LaravelSimplePermissions\SimplePermissionsServiceProvider"This will publish:
config/simple-permissions.php- Configuration file- Database migrations
Add the HasPermissions trait to your User model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Squareetlabs\LaravelSimplePermissions\Traits\HasPermissions;
class User extends Model
{
use HasPermissions;
// ... rest of your code
}
⚠️ IMPORTANT: Always do backups before running migrations.
php artisan migrateNote
If you wish to use custom foreign keys and table names, modify config/simple-permissions.php before running migrations.
To improve performance, enable caching in .env:
SIMPLE_PERMISSIONS_CACHE_ENABLED=true
SIMPLE_PERMISSIONS_CACHE_DRIVER=redis
SIMPLE_PERMISSIONS_CACHE_TTL=3600To log all permission actions:
SIMPLE_PERMISSIONS_AUDIT_ENABLED=true
SIMPLE_PERMISSIONS_AUDIT_LOG_CHANNEL=stackThe configuration file config/simple-permissions.php contains all options:
'models' => [
'user' => App\Models\User::class,
// ... other models
],'cache' => [
'enabled' => env('SIMPLE_PERMISSIONS_CACHE_ENABLED', true),
'driver' => env('SIMPLE_PERMISSIONS_CACHE_DRIVER', 'redis'),
'ttl' => env('SIMPLE_PERMISSIONS_CACHE_TTL', 3600),
'prefix' => 'simple_permissions',
'tags' => true,
],use Squareetlabs\LaravelSimplePermissions\Support\Facades\SimplePermissions;
// Create permissions
$viewPost = SimplePermissions::model('permission')::create(['code' => 'posts.view', 'name' => 'View Posts']);
$createPost = SimplePermissions::model('permission')::create(['code' => 'posts.create', 'name' => 'Create Posts']);
// Create role
$adminRole = SimplePermissions::model('role')::create(['code' => 'admin', 'name' => 'Administrator']);
// Assign permissions to role
$adminRole->permissions()->attach([$viewPost->id, $createPost->id]);// Assign role to user
$user->assignRole('admin');
// Remove role from user
$user->removeRole('admin');
// Sync roles (replaces all existing roles)
$user->syncRoles(['admin', 'editor']);// Check if user has a permission (direct or via role/group)
if ($user->hasPermission('posts.create')) {
// User can create posts
}
// Check if user has a role
if ($user->hasRole('admin')) {
// User is admin
}
// Check specific ability on an entity
if ($user->hasAbility('edit', $post)) {
// User can edit this specific post
}The HasPermissions trait provides the following methods:
// Check if user has a role (or roles)
// $require = true: all roles are required
// $require = false: at least one of the roles
$user->hasRole('admin', $require = false)
$user->hasRole(['admin', 'editor'], $require = false)
// Check if user has a permission (or permissions)
// $require = true: all permissions are required
// $require = false: at least one of the permissions
$user->hasPermission('posts.create', $require = false)
$user->hasPermission(['posts.create', 'posts.edit'], $require = false)
// Check if user has an ability on an entity
$user->hasAbility('posts.edit', $post)
// Allow ability for user on an entity
$user->allowAbility('posts.edit', $post)
// Forbid ability for user on an entity
$user->forbidAbility('posts.edit', $post)
// Remove ability from user
$user->removeAbility('posts.edit', $post)You can use wildcards for permissions:
posts.*- All permissions starting withposts.*- All permissions (if enabled in config)
// Check multiple permissions (OR)
if ($user->hasPermission(['posts.create', 'posts.edit'], false)) {
// User can create OR edit posts
}
// Check multiple permissions (AND)
if ($user->hasPermission(['posts.create', 'posts.edit'], true)) {
// User can create AND edit posts
}Abilities allow specific permissions for individual entities.
You can use helper methods for easier ability management:
// Allow user to edit a specific post
$user->allowAbility('posts.edit', $post);
// Forbid user to edit a specific post
$user->forbidAbility('posts.edit', $post);
// Remove ability from user
$user->removeAbility('posts.edit', $post);Or use the direct approach:
use Squareetlabs\LaravelSimplePermissions\Support\Facades\SimplePermissions;
// Create a permission first
$permission = SimplePermissions::model('permission')::create(['code' => 'posts.edit']);
// Create an ability for a specific entity
$ability = SimplePermissions::model('ability')::create([
'permission_id' => $permission->id,
'title' => 'Edit Post #1',
'entity_id' => $post->id,
'entity_type' => get_class($post),
]);
// Allow user to edit a specific post
$ability->users()->attach($user, ['forbidden' => false]);
// Forbid user to edit a specific post
$ability->users()->attach($user, ['forbidden' => true]);
// Remove ability from user
$ability->users()->detach($user);if ($user->hasAbility('posts.edit', $post)) {
// User can edit this specific post
}Groups allow organizing users with shared permissions.
use Squareetlabs\LaravelSimplePermissions\Support\Facades\SimplePermissions;
// Create group
$group = SimplePermissions::model('group')::create(['code' => 'moderators', 'name' => 'Moderators']);
// Assign permissions to group
$permission = SimplePermissions::model('permission')::where('code', 'posts.moderate')->first();
$group->permissions()->attach($permission);
// Add users to group
$group->users()->attach($user);
// Remove users from group
$group->users()->detach($user);The package provides middleware for route protection.
// Check role
Route::middleware(['role:admin'])->group(function () {
Route::get('/admin', [AdminController::class, 'index']);
});
// Check permission
Route::middleware(['permission:posts.create'])->group(function () {
Route::post('/posts', [PostController::class, 'store']);
});
// Check ability
// Format: ability:action,entity_class,route_parameter_name
Route::middleware(['ability:edit,App\Models\Post,post_id'])->group(function () {
Route::put('/posts/{post_id}', [PostController::class, 'update']);
});// User must have admin OR root
Route::middleware(['role:admin|root'])->group(function () {
// ...
});The package includes Blade directives for permission checks in views:
{{-- Check role --}}
@role('admin')
<button>Admin Panel</button>
@endrole
{{-- Check permission --}}
@permission('posts.create')
<a href="{{ route('posts.create') }}">New Post</a>
@endpermission
{{-- Check ability --}}
@ability('edit', $post)
<button>Edit Post</button>
@endabilityThe package integrates with Laravel's Policy system.
php artisan permissions:policy PostPolicy --model=Post// In a controller
if ($user->can('view', $post)) {
// User can view the post
}
// In a view
@can('update', $post)
<button>Edit</button>
@endcanThe package dispatches events when permissions change, allowing you to hook into these actions:
RoleAssigned: Dispatched when a role is assigned to a userRoleRemoved: Dispatched when a role is removed from a userAbilityGranted: Dispatched when an ability is granted to a userAbilityRevoked: Dispatched when an ability is revoked from a user
use Squareetlabs\LaravelSimplePermissions\Events\RoleAssigned;
use Squareetlabs\LaravelSimplePermissions\Events\AbilityGranted;
// In your EventServiceProvider
protected $listen = [
RoleAssigned::class => [
// Your listeners here
],
AbilityGranted::class => [
// Your listeners here
],
];use Squareetlabs\LaravelSimplePermissions\Events\RoleAssigned;
class LogRoleAssignment
{
public function handle(RoleAssigned $event)
{
// Log the role assignment
Log::info("User {$event->user->id} was assigned role {$event->role->code}");
}
}The package includes several useful commands:
// List all roles
php artisan permissions:roles
// Show role details
php artisan permissions:show-role {role}
// List all permissions
php artisan permissions:list
// Sync permissions from configuration
php artisan permissions:sync
// Export permissions
php artisan permissions:export --format=json
// Import permissions
php artisan permissions:import --file=permissions.json
// Clear permissions cache
php artisan permissions:clear-cache
// Generate a policy
php artisan permissions:policy PostPolicy --model=Post