The most advanced, enterprise-grade permission management system for Laravel applications.
RBAC + ABAC + Role Hierarchy + Multi-Tenancy + Audit Logging + Condition Engine
Most Laravel permission packages only offer basic RBAC. This package goes far beyond that, combining RBAC + ABAC + Policy-based authorization + Role Hierarchy + Multi-Tenancy into a single, cohesive engine.
// Basic RBAC
$user->hasRole('admin');
$user->hasPermissionTo('users.edit');
// Direct permissions with expiry
$user->givePermissionTo('reports.export', expiresAt: now()->addDay());
// Role hierarchy - editor inherits all permissions from viewer
$editor->inheritFrom('viewer');
// Explicit deny overrides everything
$user->denyPermissionTo('users.delete');
// ABAC - contextual permissions
$user->canPermission('posts.update', $post);
// Only if $post->owner_id === $user->id AND $post->status === 'draft'
// Multi-tenancy - different roles per team
$user->assignRoleForTeam('admin', $engineeringTeam);
$user->assignRoleForTeam('editor', $marketingTeam);
// Audit trail - who did what, when
PermissionAudit::byActor($admin->id)->action('granted')->get();
// Explain API - debug why access was denied
PermissionManager::explain($user, 'orders.delete');
users.*, *.edit, !users.delete)web, api, admin)eval()Gate::before() integration@role, @permission, @hasAnyRole, @unlessPermissionpm:permission:any:edit,view, role:admin|managerPermissionManager::user(), ::role(), ::explain()permission:doctor, permission:why, permission:treeactingAsRole(), assertHasPermission()composer require hosseinhezami/laravel-permission-manager
php artisan vendor:publish --provider="HosseinHezami\PermissionManager\PermissionManagerServiceProvider" --tag="config"
php artisan vendor:publish --provider="HosseinHezami\PermissionManager\PermissionManagerServiceProvider" --tag="migrations"
php artisan migrate
This creates 14 tables:
roles, permissions, permission_groups, permission_sets, permission_set_itemsrole_permissions, role_inheritsuser_roles, user_permissionsteams, team_userpermission_conditions, permission_audits, authorization_logsnamespace App\Models;
use HosseinHezami\PermissionManager\Traits\PermissionTrait;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use PermissionTrait;
}
php artisan permission-manager:install --migrate
use HosseinHezami\PermissionManager\Models\Role;
$admin = Role::create([
'name' => 'Administrator',
'slug' => 'admin',
'description' => 'Full system access',
]);
Or via CLI:
php artisan role:create admin "Administrator" "Full system access"
use HosseinHezami\PermissionManager\Models\Permission;
Permission::create(['route' => 'users.view']);
Permission::create(['route' => 'users.edit']);
Permission::create(['route' => 'users.delete']);
Or sync all your routes automatically:
php artisan permission:sync-routes
$admin->assignPermission(['users.view', 'users.edit']);
// Or with wildcard
$admin->assignPermission('users.*');
$user = User::find(1);
$user->assignRole('admin');
// Check permissions
$user->hasPermissionTo('users.edit'); // true
$user->hasPermissionTo('users.delete'); // false
// Single permission
Route::get('/users', [UserController::class, 'index'])
->middleware('pm:permission:users.view');
// Any of these permissions
Route::get('/users', [UserController::class, 'index'])
->middleware('pm:permission:any:users.view,users.list');
// All of these permissions
Route::post('/users', [UserController::class, 'store'])
->middleware('pm:permission:all:users.view,users.create');
// Role check
Route::get('/admin', function () { /* ... */ })
->middleware('pm:role:admin|manager');
@role('admin')
<a href="">Dashboard</a>
@endrole
@permission('users.edit')
<button>Edit User</button>
@endpermission
@unlesspermission('users.delete')
<span class="text-muted">Delete disabled</span>
@endunlesspermission
// Create role
$editor = Role::create(['name' => 'Editor', 'slug' => 'editor']);
// Create permission
$permission = Permission::create(['route' => 'posts.publish']);
// Assign permission to role
$editor->assignPermission('posts.publish');
// Assign role to user
$user->assignRole('editor');
// Check
$user->hasRole('editor'); // true
$user->hasPermissionTo('posts.publish'); // true
Sometimes you need to grant a permission to a specific user without creating a role:
// Give a one-time permission
$user->givePermissionTo('reports.export');
// Check direct permission
$user->hasDirectPermission('reports.export'); // true
// Revoke
$user->revokePermissionTo('reports.export');
Why it matters: Perfect for exceptional cases, temporary access, or overriding role-based permissions.
The deny permission has higher priority than allow. This is powerful for exceptions:
// Role grants all posts.* permissions
$editor->assignPermission('posts.*');
// But deny deleting posts specifically
$user->denyPermissionTo('posts.delete');
// Result
$user->hasPermissionTo('posts.edit'); // true (from role)
$user->hasPermissionTo('posts.delete'); // false (explicit deny overrides)
1. Super Admin bypass (if configured)
2. Explicit User DENY
3. Explicit Role DENY
4. Explicit User ALLOW
5. Role ALLOW
6. Inherited Role permissions
7. Default: DENY
Roles can inherit permissions from other roles, creating a hierarchy:
// Create hierarchy: super-admin > admin > editor > viewer
$superAdmin = Role::create(['name' => 'Super Admin', 'slug' => 'super-admin']);
$admin = Role::create(['name' => 'Admin', 'slug' => 'admin']);
$editor = Role::create(['name' => 'Editor', 'slug' => 'editor']);
$viewer = Role::create(['name' => 'Viewer', 'slug' => 'viewer']);
// Assign specific permissions
$viewer->assignPermission('posts.view');
$editor->assignPermission('posts.edit');
$admin->assignPermission('posts.delete');
$superAdmin->assignPermission('system.config');
// Build hierarchy
$admin->inheritFrom('editor'); // admin gets editor's permissions
$editor->inheritFrom('viewer'); // editor gets viewer's permissions
$superAdmin->inheritFrom('admin'); // super-admin gets admin's permissions
// A user with super-admin role now has ALL permissions
$user->assignRole('super-admin');
$user->hasPermissionTo('posts.view'); // โ
from viewer (via editor โ admin)
$user->hasPermissionTo('posts.edit'); // โ
from editor (via admin)
$user->hasPermissionTo('posts.delete'); // โ
from admin
$user->hasPermissionTo('system.config'); // โ
from super-admin
The system automatically prevents circular inheritance:
$roleA->inheritFrom('roleB');
$roleB->inheritFrom('roleA'); // โ Throws CyclicRoleInheritanceException
Use wildcards for flexible permission matching:
// Match any route starting with 'users.'
$role->assignPermission('users.*');
// Now the user has:
$user->hasPermissionTo('users.view'); // true
$user->hasPermissionTo('users.edit'); // true
$user->hasPermissionTo('users.delete'); // true
// Match routes ending with '.edit'
$role->assignPermission('*.edit');
$user->hasPermissionTo('posts.edit'); // true
$user->hasPermissionTo('users.edit'); // true
// Global wildcard (DANGEROUS - use carefully!)
$role->assignPermission('*'); // All permissions
// Negation - deny specific pattern
$role->assignPermission('!users.delete');
| Pattern | Matches | Doesnโt Match |
|---|---|---|
users.* |
users.edit, users.delete |
posts.edit |
*.edit |
users.edit, posts.edit |
users.view |
users.{id}.edit |
users.42.edit |
users.edit |
* |
everything | nothing |
!users.delete |
everything except users.delete |
users.delete |
Perfect for SaaS applications where users belong to multiple teams:
use HosseinHezami\PermissionManager\Models\Team;
// Create teams
$engineering = Team::createTeam(['name' => 'Engineering', 'slug' => 'engineering']);
$marketing = Team::createTeam(['name' => 'Marketing', 'slug' => 'marketing']);
// User joins both teams
$user->joinTeam($engineering);
$user->joinTeam($marketing);
// Assign different roles per team
$user->assignRoleForTeam('admin', $engineering);
$user->assignRoleForTeam('editor', $marketing);
// Check team-specific roles
$user->hasRoleForTeam('admin', $engineering); // true
$user->hasRoleForTeam('admin', $marketing); // false
$user->hasRoleForTeam('editor', $marketing); // true
Set the current team context via middleware:
// In routes/api.php
Route::middleware(['pm.team:header,X-Team-Id'])->group(function () {
// All permissions in this group are scoped to the team from X-Team-Id header
});
Or programmatically:
use HosseinHezami\PermissionManager\Facades\PermissionManager;
PermissionManager::setTeam($currentTeam);
// All subsequent permission checks are scoped to this team
Attribute-Based Access Control lets you define dynamic conditions:
use HosseinHezami\PermissionManager\Models\PermissionCondition;
$permission = Permission::create(['route' => 'posts.update']);
// Only allow updates if user is the post owner AND status is draft
PermissionCondition::create([
'permission_id' => $permission->id,
'name' => 'owner-and-draft',
'conditions' => [
'all' => [
['field' => 'user.id', 'operator' => '=', 'value' => 'resource.owner_id'],
['field' => 'resource.status', 'operator' => '=', 'value' => 'draft'],
],
],
]);
// Usage
$user->givePermissionTo('posts.update');
$post = Post::find(1);
$user->canPermission('posts.update', $post);
// Returns true only if $user->id === $post->owner_id AND $post->status === 'draft'
| Operator | Description | Example |
|---|---|---|
= == |
Equal | user.id = resource.owner_id |
!= !== |
Not equal | user.role != "banned" |
> >= |
Greater than | user.level >= resource.required_level |
< <= |
Less than | user.failed_attempts < 3 |
in |
In array | resource.status in ["draft", "pending"] |
not_in |
Not in array | user.id not_in [1, 2, 3] |
contains |
String contains | user.email contains "@company.com" |
starts_with |
String starts with | resource.path starts_with "admin/" |
ends_with |
String ends with | resource.mime ends_with "pdf" |
exists |
Is not null | resource.published_at exists |
not_exists |
Is null | resource.deleted_at not_exists |
// AND logic (all must match)
['all' => [
['field' => 'user.id', 'operator' => '=', 'value' => 'resource.owner_id'],
['field' => 'resource.status', 'operator' => '=', 'value' => 'draft'],
]]
// OR logic (any must match)
['any' => [
['field' => 'user.id', 'operator' => '=', 'value' => 'resource.owner_id'],
['field' => 'user.is_admin', 'operator' => '=', 'value' => true],
]]
// NOT logic
['not' => [
'field' => 'resource.status',
'operator' => '=',
'value' => 'archived',
]]
// Complex nesting
['all' => [
['field' => 'resource.status', 'operator' => '!=', 'value' => 'archived'],
['any' => [
['field' => 'user.id', 'operator' => '=', 'value' => 'resource.owner_id'],
['field' => 'user.role', 'operator' => '=', 'value' => 'admin'],
]],
]]
Grant time-limited access:
// Give permission that expires in 24 hours
$user->givePermissionTo(
'reports.export',
'allow',
now()->addDay()
);
// Permission is valid until expiration
$user->hasPermissionTo('reports.export'); // true now
// After 24 hours: false (automatically)
// Prune expired permissions (run as scheduled job)
php artisan permission:prune --days=7
Track who changed what and when:
use HosseinHezami\PermissionManager\Models\PermissionAudit;
// Automatically logged when you:
$user->assignRole('admin');
$role->assignPermission('users.delete');
$user->givePermissionTo('reports.export');
// Query audit log
$recentChanges = PermissionAudit::latest()
->limit(50)
->get();
// Filter by actor (who made the change)
$adminChanges = PermissionAudit::byActor($adminId)->get();
// Filter by action
$grants = PermissionAudit::action('granted')->get();
// Each audit includes:
// - actor_id: who made the change
// - action: what happened (granted, revoked, created, etc.)
// - subject_type: user, role, permission
// - subject_id: the target of the action
// - ip_address: where it came from
// - user_agent: browser info
// - metadata: extra data
// config/permission-manager.php
'audit' => [
'enabled' => true,
'log_mutations' => true,
],
Optionally log every permission check (useful for security audits):
// config/permission-manager.php
'authorization_logging' => [
'enabled' => true,
'denied_only' => true, // Only log failed attempts
'sample_rate' => 0.1, // Log 10% of checks (for high-traffic apps)
],
Isolate permissions by authentication guard:
// Create web-only role
Role::create([
'name' => 'Web Admin',
'slug' => 'web-admin',
'guard_name' => 'web',
]);
// Create API-only role
Role::create([
'name' => 'API Admin',
'slug' => 'api-admin',
'guard_name' => 'api',
]);
// Query by guard
$webRoles = Role::forGuard('web')->get();
$apiRoles = Role::forGuard('api')->get();
// Permissions are also guard-scoped
Permission::forGuard('api')->get();
Advanced middleware with a powerful DSL:
// Single permission
Route::get('/users', fn() => '...')->middleware('pm:permission:users.view');
// ANY of these (OR logic)
Route::get('/users', fn() => '...')
->middleware('pm:permission:any:users.view,users.list,users.index');
// ALL of these (AND logic)
Route::post('/users', fn() => '...')
->middleware('pm:permission:all:users.view,users.create');
// NOT this permission
Route::get('/public', fn() => '...')
->middleware('pm:permission:not:admin.panel');
// Single role
Route::get('/admin', fn() => '...')->middleware('pm:role:admin');
// ANY of these roles (OR logic)
Route::get('/staff', fn() => '...')
->middleware('pm:role:any:admin,manager,editor');
// ALL of these roles (AND logic) - user must have ALL
Route::get('/privileged', fn() => '...')
->middleware('pm:role:all:verified,premium');
// Multiple directives (AND logic between them)
Route::get('/reports', fn() => '...')
->middleware([
'pm:role:admin',
'pm:permission:reports.view',
]);
// Using pipe (|) for OR
Route::get('/staff', fn() => '...')
->middleware('role:admin|manager|editor');
// Using comma (,) for AND
Route::get('/premium', fn() => '...')
->middleware('role:verified,premium');
@role('admin')
<span>Welcome, Administrator!</span>
@endrole
@hasanyrole(['admin', 'editor'])
<span>You can edit content</span>
@endhasanyrole
@hasallroles(['verified', 'premium'])
<span>Premium Verified User</span>
@endhasallroles
@unlessrole('banned')
<span>You are not banned</span>
@endunlessrole
@permission('users.edit')
<button>Edit User</button>
@endpermission
@hasanypermission(['users.edit', 'users.delete'])
<span>You can modify users</span>
@endhasanypermission
@hasallpermissions(['users.view', 'users.edit', 'users.delete'])
<span>Full user management access</span>
@endhasallpermissions
@unlesspermission('users.delete')
<span>Delete permission required</span>
@endunlesspermission
@cannotpermission('users.delete')
<span>Cannot delete users</span>
@endcannotpermission
@canpermission('posts.update', $post)
<a href="">Edit Post</a>
@endcanpermission
@hasRole('admin') ... @endHasRole
@hasPermission('users.edit') ... @endHasPermission
All permissions are automatically registered with Laravelโs Gate:
// All these work out of the box:
$user->can('users.edit');
$user->cannot('users.delete');
// In Blade
@can('users.edit')
<button>Edit</button>
@endcan
// In Controllers
Gate::authorize('users.edit');
Gate::allows('users.edit');
Gate::denies('users.delete');
Define custom abilities with complex logic:
use HosseinHezami\PermissionManager\Facades\PermissionManager;
PermissionManager::define('posts.update', function ($user, $post) {
return $post->user_id === $user->id
|| $user->hasPermissionTo('posts.edit.any');
});
// Usage
$user->canPermission('posts.update', $post);
Get detailed explanations of authorization decisions:
$result = PermissionManager::explain($user, 'orders.delete');
// Returns:
[
'allowed' => false,
'ability' => 'orders.delete',
'reason' => 'explicit_user_deny',
'source' => 'direct_permission',
'metadata' => [
'matched_pattern' => 'orders.delete',
'permission_id' => 42,
],
'user' => [
'id' => 1,
'roles' => ['admin', 'editor'],
'direct_permissions' => ['orders.view', '!orders.delete'],
],
]
use HosseinHezami\PermissionManager\Facades\PermissionManager;
// List all roles
$roles = PermissionManager::roles()->list();
// Create role
PermissionManager::roles()->create([
'slug' => 'editor',
'name' => 'Editor',
'description' => 'Can edit content',
]);
// Role operations via proxy
PermissionManager::role('admin')
->assignPermission('users.*')
->assignPermissionSet('content-manager')
->inheritFrom('editor');
// Update, delete
PermissionManager::role('editor')->update(['name' => 'Content Editor']);
PermissionManager::role('editor')->delete();
// List all permissions
$permissions = PermissionManager::permissions()->list();
// Create
PermissionManager::permissions()->create('users.view');
PermissionManager::permissions()->create(['users.edit', 'users.delete']);
// Delete
PermissionManager::permissions()->delete('users.delete');
// Sync with routes
PermissionManager::permissions()->sync();
// Get grouped by category
$grouped = PermissionManager::permissions()->getAllGrouped();
// Permission sets
PermissionManager::permissions()->createSet([
'name' => 'Content Manager',
'slug' => 'content-manager',
]);
// User operations
PermissionManager::user($userId)
->assignRole('admin')
->assignRole(['editor', 'manager'])
->givePermissionTo('reports.export');
// Queries
$roles = PermissionManager::user($userId)->roles();
$permissions = PermissionManager::user($userId)->permissions();
$canEdit = PermissionManager::user($userId)->hasPermission('users.edit');
// Set current team
PermissionManager::setTeam($team);
PermissionManager::setTeam(42); // By ID
PermissionManager::setTeam('engineering'); // By slug
// Clear team context
PermissionManager::clearTeam();
// Get current team context
$teamContext = PermissionManager::teamContext();
// Clear all permission cache
PermissionManager::cache()->flushAll();
// Clear specific user cache
PermissionManager::cache()->flushUser($userId);
// Clear specific role cache
PermissionManager::cache()->flushRole($roleId);
# List all roles
php artisan roles:list
# Create a role
php artisan role:create admin "Administrator" "Full access"
# Update a role
php artisan role:update admin --name="Super Admin"
# Delete a role
php artisan role:delete admin
# List permissions
php artisan permissions:list
# Create permissions
php artisan permission:create "users.edit"
php artisan permission:create "users.create,users.edit,users.delete"
# Delete permissions
php artisan permission:delete "users.delete"
# Sync routes with permissions
php artisan permission:sync-routes
php artisan permission:sync-routes --strategy=controller-action
php artisan permission:sync-routes --prefix=admin
# Generate CRUD permissions for a resource
php artisan permission:generate-resource users
php artisan permission:generate-resource Post --actions=view,create,update
# Assign permissions to role
php artisan role:assign-permission admin "users.*"
php artisan role:assign-permission admin "users.create,users.edit"
# Revoke permissions
php artisan role:revoke-permission admin "users.delete"
# Assign roles to user
php artisan user:assign-role 1 admin
php artisan user:assign-role 1 "admin,editor"
# Revoke roles from user
php artisan user:revoke-role 1 admin
# Export roles to JSON
php artisan role:export roles.json
# Import roles from JSON
php artisan role:import roles.json
# ๐ฉบ System health check
php artisan permission:doctor
# Detects:
# - Orphan permissions (not assigned to any role)
# - Orphan roles (not assigned to any user)
# - Cyclic role inheritance
# - Duplicate roles/permissions
# - Expired permissions
# ๐ณ View role hierarchy tree
php artisan permission:tree
php artisan permission:tree --role=admin
# โ Why was access denied?
php artisan permission:why 42 users.delete
# Output:
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# โ Permission Decision Explanation โ
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# User: 42
# Ability: users.delete
# โ DENIED
# Reason: explicit_user_deny
# Source: direct_permission
# Details:
# - matched_pattern: users.delete
# - permission_id: 15
# ๐ Explain permission check (JSON output)
php artisan permission:explain 42 users.edit --json
# โ
Validate configuration
php artisan permission:validate
# โ๏ธ Prune expired permissions
php artisan permission:prune --days=30
php artisan permission:prune --dry-run
# โก Check single permission
php artisan permission:check 42 users.edit
# Warm up cache (preload all permissions)
php artisan permission:cache:warm
# Clear cache
php artisan permission:cache:clear
php artisan permission:cache:clear --user=42
php artisan permission:cache:clear --role=5
The package provides powerful testing helpers for your application tests:
use HosseinHezami\PermissionManager\Testing\InteractsWithPermissions;
use HosseinHezami\PermissionManager\Testing\PermissionAssertions;
class PostControllerTest extends TestCase
{
use InteractsWithPermissions;
use PermissionAssertions;
// ...
}
// Create user with roles
$admin = $this->createUserWithRoles(['admin', 'editor']);
// Create role with permissions
$role = $this->createRoleWithPermissions('editor', [
'posts.view',
'posts.edit',
'posts.publish',
]);
// Act as a user with specific roles
$user = $this->actingAsRole(['admin']);
// Act as a user with specific permissions
$user = $this->actingAsWithPermissions(['posts.view', 'posts.edit']);
// Grant / deny permissions in tests
$this->grantPermission($user, 'posts.edit');
$this->denyPermission($user, 'posts.delete');
// Clear cache
$this->clearPermissionCache();
public function test_admin_can_edit_posts()
{
$admin = $this->createUserWithRoles(['admin']);
$this->assertHasRole($admin, 'admin');
$this->assertHasPermission($admin, 'posts.edit');
$this->assertDoesNotHavePermission($admin, 'system.config');
$this->assertHasAnyRole($admin, ['admin', 'editor']);
$this->assertHasAllRoles($admin, ['admin']);
$this->assertHasAnyPermission($admin, ['posts.edit', 'posts.view']);
$this->assertHasAllPermissions($admin, ['posts.edit']);
$this->assertIsNotSuperAdmin($admin);
// Test contextual permissions
$post = Post::factory()->create(['user_id' => $admin->id]);
$this->assertCanPermission($admin, 'posts.update', $post);
}
public function test_unauthorized_user_gets_403()
{
$user = $this->createUser();
$this->actingAs($user)
->get('/admin/users')
->assertStatus(403);
}
public function test_authorized_user_gets_access()
{
$user = $this->actingAsRole(['admin']);
$this->get('/admin/users')
->assertStatus(200);
}
Full configuration file (config/permission-manager.php):
return [
// Model classes
'models' => [
'role' => \HosseinHezami\PermissionManager\Models\Role::class,
'permission' => \HosseinHezami\PermissionManager\Models\Permission::class,
'user' => config('auth.providers.users.model'),
'team' => \HosseinHezami\PermissionManager\Models\Team::class,
],
// Table names
'tables' => [
'roles' => 'roles',
'permissions' => 'permissions',
'permission_groups' => 'permission_groups',
'permission_sets' => 'permission_sets',
'permission_set_items' => 'permission_set_items',
'role_permissions' => 'role_permissions',
'role_inherits' => 'role_inherits',
'user_roles' => 'user_roles',
'user_permissions' => 'user_permissions',
'teams' => 'teams',
'team_user' => 'team_user',
'permission_conditions' => 'permission_conditions',
'permission_audits' => 'permission_audits',
'authorization_logs' => 'authorization_logs',
],
// Cache settings
'cache_duration' => 60, // minutes
'cache' => [
'enabled' => true,
'prefix' => 'pm',
'use_tags' => false, // Enable for Redis/Memcached
'ttl' => 60,
],
// Feature toggles
'wildcards' => true,
'log_denials' => false,
'direct_permissions' => ['enabled' => true],
'teams' => [
'enabled' => true,
'team_foreign_key' => 'team_id',
],
// Super Admin
'super_admin' => [
'enabled' => true,
'role_slug' => 'super-admin',
'bypass_all' => true,
],
// Audit
'audit' => [
'enabled' => true,
'log_mutations' => true,
],
// Authorization logging (use with caution in production)
'authorization_logging' => [
'enabled' => false,
'denied_only' => true,
'sample_rate' => 1.0,
],
// ABAC
'conditions' => ['enabled' => true],
// Route sync
'route_sync' => [
'enabled' => true,
'strategy' => 'route-name', // route-name | controller-action | resource-action
],
];
| Feature | Laravel Permission Manager | Spatie Permission | Winner |
|---|---|---|---|
| RBAC | โ | โ | Tie |
| Direct Permissions | โ | โ | Tie |
| Wildcard Permissions | โ (advanced) | โ | LPM |
| Role Hierarchy | โ Multi-level | โ | LPM |
| Explicit Deny | โ | โ | LPM |
| Temporary Permissions | โ | โ | LPM |
| Teams / Multi-Tenancy | โ | โ | Tie |
| Multi-Guard | โ Real isolation | โ | Tie |
| ABAC (Condition Engine) | โ | โ | LPM |
| Audit Logging | โ Built-in | โ | LPM |
| Authorization Audit Trail | โ | โ | LPM |
| Route Sync | โ | โ | LPM |
| Resource Generator | โ | โ | LPM |
| Explain API | โ | โ | LPM |
| CLI Doctor | โ | โ | LPM |
| Permission Tree | โ | โ | LPM |
| Gate Integration | โ Native | โ | Tie |
| Middleware DSL | โ Advanced | โ | Tie |
| Cache Tags | โ | โ | Tie |
| Admin UI | ๐ Roadmap | โ | Tie |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Your App โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โ
โ โ Blade โ โMiddlewareโ โ Controllers โ โ
โ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโโโโโฌโโโโโโโโโ โ
โ โ โ โ โ
โโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AuthorizationManager (Core Engine) โ
โ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ Wildcard โ โ Condition โ โ Policy โ โ
โ โ Matcher โ โ Evaluator โ โ Resolver โ โ
โ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ Role โ โ Permission โ โ Context โ โ
โ โ Resolver โ โ Resolver โ โ Resolver โ โ
โ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Data Layer โ
โ โโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโโ โ
โ โ Roles โ โPermissionsโ โ Teams โ โ Audits โ โ
โ โโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Contributions are welcome! Please read CONTRIBUTING.md for details.
# Clone repository
git clone https://github.com/hosseinhezami/laravel-permission-manager.git
cd laravel-permission-manager
# Install dependencies
composer install
# Run tests
composer test
# Run specific test suites
composer test-unit
composer test-feature
composer test-integration
# All tests
composer test
# With coverage
composer test-coverage
The MIT License (MIT). Please see License File for more information.
If this package helps you, please:
Made with โค๏ธ by Hossein Hezami