salvatorecervone / rolepermissionmanager
A dynamic, database-driven Role & Permission Manager for Laravel. Replaces static middleware-based permission checks with a centralized, zero-hardcoding ACL system.
Package info
github.com/SalvatoreCervone/rolepermissionmanager
pkg:composer/salvatorecervone/rolepermissionmanager
Requires
- php: ^8.2
- illuminate/auth: ^10.0|^11.0|^12.0
- illuminate/cache: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v1.4.7
- v1.4.6
- v1.4.5
- v1.4.4
- v1.4.3
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.14
- v1.3.13
- v1.3.12
- v1.3.11
- v1.3.10
- v1.3.9
- v1.3.8
- v1.3.7
- v1.3.6
- v1.3.5
- v1.3.4
- v1.3.3
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.4
- v1.1.3
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.9
- v1.0.8
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
This package is auto-updated.
Last update: 2026-09-12 17:36:17 UTC
README
A modern, dynamic, database-driven Role & Permission Manager for Laravel that completely replaces static middleware annotations with a centralized, zero-hardcoding Access Control Layer (ACL).
๐ก 100% Automatic โ Zero Code Changes & Coexistence
In traditional authorization setups, permissions are hardcoded into route definitions, controller constructors, or method calls:
// โ Hardcoded permissions in code Route::delete('/invoices/{id}', [InvoiceController::class, 'destroy']) ->middleware('permission:delete-invoices');
When business rules change, developers must edit controllers, routes, commit, and deploy.
RolePermissionManager eliminates this entirely:
- โก Zero Code Modifications โ No need to add traits, modify controllers, or annotate routes.
- ๐ก๏ธ Coexists with Existing Systems โ No need to remove or refactor your existing roles, permissions, or database tables. RolePermissionManager uses isolated tables (
acl_*) and a non-intrusive dynamic interceptor. - ๐ Instant Runtime Updates โ Change any permission rule from the built-in Web Admin Panel in seconds with zero code changes and zero downtime.
โจ Features
- ๐ Zero Hardcoding โ Define clean routes without cluttering them with
permission:...middleware - ๐ก๏ธ Zero-Trust Auto-Discovery (
AclRegistry::protect()) โ Protect any controller method, service, or business action with a single line of code. Automatically detects the caller and locks access (HTTP 403 for everyone, including Super Admin) until configured in the panel - ๐ฏ Granular Route Parameter Rules โ Secure URI placeholders (e.g.
/reports/{page}) with specific permissions per parameter value and customizable fallback policies (404 Not Found, 403 Forbidden, or Pass-through) - ๐ Route Auto-Discovery โ
php artisan acl:syncscans your routes and registers new endpoints automatically - ๐ฆ Custom Resources Support โ Create, manage, and protect arbitrary classes, methods, services, or UI actions from the panel
- ๐ฒ Interactive Role-Permission Matrix โ Spreadsheet-style pivot matrix (
/acl-admin/matrix) with real-time AJAX permission toggling - ๐ Access Simulator & Diagnostic Tester โ Test user authorization step-by-step from both the UI (
/acl-admin/simulator) and CLI (php artisan acl:check) - ๐พ JSON Export & Import โ Seamlessly transfer entire ACL configurations across environments (Local โ Staging โ Production) via web UI or CLI (
php artisan acl:export/acl:import) - โก Bulk Actions on Routes & Resources โ Mass-assign permissions, set Super Admin only flags, or change visibility with one click
- ๐ Audit Trail & Activity Log โ Complete history tracking of who changed which role, permission, or route (
/acl-admin/audit-logs) - โฐ Automated Scheduler โ Configurable daily route synchronization to catch new endpoints
- ๐ก๏ธ Single Dynamic Interceptor โ
DynamicAclGuardmiddleware evaluates requests against cached ACL rules - โก High Performance & Low Latency โ Complete cache layer (Redis/File/Memory) with automatic invalidation on Eloquent events (0 DB queries per request)
- ๐๏ธ AND / OR Permission Operators โ Choose whether a resource requires all or at least one of the linked permissions
- ๐ Super Admin Bypass & Dedicated Protection โ Configurable super admin role that bypasses checks, plus a single-click toggle to reserve any route/resource exclusively for Super Admins
- ๐ค User Access Management โ Manage user roles and direct permissions with multi-column display support (e.g.
['name', 'cognome']) and live autocomplete - ๐จ Blade Directives โ
@role,@haspermission,@canRoute, and@canResourcefor views - ๐ Native Laravel Gate Integration โ Works seamlessly with
$user->can()and@can - ๐ฆ Polymorphic Architecture โ Works with any Authenticatable model (User, Admin, Member, etc.)
๐ Requirements
- PHP:
^8.2 - Laravel:
^10.0 | ^11.0 | ^12.0
๐ฆ Installation
1. Require the package via Composer
composer require salvatorecervone/rolepermissionmanager
2. Publish Assets
You can publish all assets at once:
php artisan vendor:publish --provider="SalvatoreCervone\RolePermissionManager\RolePermissionManagerServiceProvider"
Or publish individual components using specific tags:
| Component | Publish Command | Target Location |
|---|---|---|
| Config (Required) | php artisan vendor:publish --tag=rolepermissionmanager-config |
config/rolepermissionmanager.php |
| Migrations (Required) | php artisan vendor:publish --tag=rolepermissionmanager-migrations |
database/migrations/ |
| Language Files (Optional) | php artisan vendor:publish --tag=rolepermissionmanager-lang |
lang/vendor/acl/ |
| Blade Views (Optional) | php artisan vendor:publish --tag=rolepermissionmanager-views |
resources/views/vendor/acl/ |
| Routes (Optional) | php artisan vendor:publish --tag=rolepermissionmanager-routes |
routes/acl-web.php & routes/acl-api.php |
3. Run Database Migrations
php artisan migrate
This creates 9 tables (customizable in config):
acl_rolesacl_permissionsacl_secured_resourcesacl_route_parameter_rules(granular parameter authorization & fallbacks)acl_scanner_rules(dynamic route exclusions & inclusions)acl_model_has_roles(polymorphic pivot)acl_model_has_permissions(polymorphic pivot)acl_role_has_permissions(pivot)acl_permission_has_resources(pivot)acl_audit_logs(audit history)
๐ Quick Start
1. (Optional) Add the Trait to your User Model
Adding HasAcl to your User model is optional โ it provides direct convenience helper methods on the user instance (e.g., $user->assignRole(), $user->hasPermission(), $user->canAccessRoute()):
namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use SalvatoreCervone\RolePermissionManager\Traits\HasAcl; class User extends Authenticatable { use HasAcl; }
Note: The dynamic middleware
DynamicAclGuard, the Admin Panel, andAclRegistrywork seamlessly even without modifying your User model.
2. Synchronize Application Routes
php artisan acl:sync --notify
Output:
๐ Scanning routes...
+-----------------------+--------+----------------------+------------------------------------------------+
| Identifier | Method | URI | Action |
+-----------------------+--------+----------------------+------------------------------------------------+
| dashboard | GET | /dashboard | App\Http\Controllers\DashboardController@index |
| invoices.index | GET | /invoices | App\Http\Controllers\InvoiceController@index |
| invoices.create | GET | /invoices/create | App\Http\Controllers\InvoiceController@create |
| invoices.store | POST | /invoices | App\Http\Controllers\InvoiceController@store |
| invoices.destroy | DELETE | /invoices/{id} | App\Http\Controllers\InvoiceController@destroy |
+-----------------------+--------+----------------------+------------------------------------------------+
โ Discovered 5 new routes. Cache refreshed.
3. Open the Web Admin Panel
Navigate to https://your-domain.com/acl-admin (protected by ['web', 'auth'] middleware by default).
From the panel you can:
- ๐ฒ Role-Permission Matrix (
/acl-admin/matrix): Toggle permissions per role in real time. - ๐ Access Simulator (
/acl-admin/simulator): Select any User and Route to run real-time authorization diagnostics. - โก Bulk Actions (
/acl-admin/routes): Select multiple routes to apply permissions or Super Admin flags in bulk. - ๐พ Export & Import (
/acl-admin/export-import): Download JSON backups or import ACL settings from other environments. - ๐ Audit Logs (
/acl-admin/audit-logs): Review full historical tracking of authorization changes. - ๐ค Users & Access (
/acl-admin/users): Assign roles and direct permissions to users with multi-model polymorphic support.
4. ๐ฅ Multi-Model / Polymorphic Support (Optional)
If your application has multiple authenticatable models (e.g. User, Admin, Staff), configure user_models in config/rolepermissionmanager.php:
'user_models' => [ 'users' => [ 'label' => 'Users', 'model' => App\Models\User::class, 'searchable_fields' => ['name', 'email'], 'display_field' => ['name', 'cognome'], 'secondary_field' => 'email', ], 'admins' => [ 'label' => 'Administrators', 'model' => App\Models\Admin::class, 'searchable_fields' => ['nome', 'cognome', 'email'], 'display_field' => ['nome', 'cognome'], 'secondary_field' => 'email', ], ],
The Web Admin Panel will automatically render model selector tabs on /acl-admin/users and within the Access Simulator!
- โ๏ธ Scanner Rules (
/acl-admin/scanner-rules): Manage route exclusions and auto-registration patterns.
๐ ๏ธ Artisan Commands
# 1. Route Synchronization php artisan acl:sync # Basic route scan and cache rebuild php artisan acl:sync --clean # Remove deprecated routes from DB php artisan acl:sync --auto-permissions # Auto-create permissions for new routes php artisan acl:sync --clean --auto-permissions --notify # Complete sync with verbose log # 2. Access Diagnostics & Simulation php artisan acl:check 1 invoices.destroy # Check user ID 1 against a route php artisan acl:check admin@company.com "CorsoController@dettagliocorsi" # 3. Export & Import Configuration php artisan acl:export # Export to storage/app/acl-export-*.json php artisan acl:export --path=/path/to/custom-backup.json php artisan acl:import /path/to/acl-export.json # Merge configuration php artisan acl:import /path/to/acl-export.json --overwrite # Overwrite existing associations
๐จ Blade Directives
RolePermissionManager provides powerful, expressive Blade directives to conditionally render UI elements based on roles, permissions, routes, and custom resources, plus an automated client-side notification engine:
1. Role Verification (@role)
Checks if the authenticated user has a specific role (by slug):
@role('admin') <a href="/admin/settings">Admin Settings</a> @else <span>Standard User Area</span> @endrole
2. Permission Verification (@haspermission)
Checks if the user has a permission (assigned directly or inherited through any of their roles):
@haspermission('invoices.export') <button class="btn btn-secondary">Export CSV</button> @endhaspermission
3. Route Authorization Check (@canRoute)
Checks if the current user is permitted to access a specific route by its name or its METHOD:uri signature:
{{-- Check by route name --}} @canRoute('invoices.destroy') <button class="btn-delete">Delete Invoice</button> @endcanRoute {{-- Check by HTTP verb + URI signature --}} @canRoute('POST:api/v1/invoices') <button class="btn-create">Create Invoice</button> @endcanRoute
4. Custom Resource Authorization Check (@canResource)
Checks if the user is authorized to access an internal class method, service, or custom ACL resource:
@canResource('CorsoController@dettagliocorsi') <button class="btn-info">View Course Details</button> @endcanResource @canResource('stampa.questori') <button class="btn-primary">Stampa Questori</button> @endcanResource
5. Automated AJAX 403 / Denial Toast Engine (@aclAlerts or @aclToast)
Place this directive once in your master application layout (e.g. resources/views/layouts/app.blade.php before </body>):
{{-- Automatic Toast / Alert Engine for AJAX / Fetch / Axios --}} @aclAlerts {{-- or @aclToast --}} </body> </html>
What it does automatically (Zero Dependencies, pure Vanilla CSS & JS):
- Seamless Interception: Automatically catches HTTP 403 (and 401) responses across:
window.axios(Axios)window.fetch(Native browser Fetch API)XMLHttpRequest(jQuery$.ajax,$.post, Vue, Livewire, Alpine.js, Inertia)
- Visual Feedback: Instantly pops up a sleek, modern floating Toast in the top-right corner with a ๐ lock icon, denial message, 5-second progress bar, and dismiss button (
โ). - Global JavaScript Event: Emits a
CustomEventonwindowallowing custom integration with libraries like SweetAlert2 or Toastr:window.addEventListener('acl:denied', (event) => { console.warn('Access denied:', event.detail.message); // Optional: hook into SweetAlert2 // Swal.fire('Access Denied', event.detail.message, 'warning'); });
(To disable the default visual toast and solely use your own modal/alert library, setwindow.ACL_DISABLE_DEFAULT_TOAST = true;before the script runs).
๐ก๏ธ Zero-Trust Auto-Discovery & Fail-Closed Protection
Protect internal controller methods, services, or sensitive business actions with a single line of code, completely eliminating human error (forgetting to register the resource or leaving methods unprotected):
use SalvatoreCervone\RolePermissionManager\Services\AclRegistry; class CorsoController extends Controller { public function esportaAnagrafica() { // 1. One line: auto-detects 'CorsoController@esportaAnagrafica' AclRegistry::protect(); // Or specify an explicit alias and optional custom user-facing message: // AclRegistry::protect('anagrafica.export', 'Accesso non consentito alla stampa anagrafica.'); // Business logic runs ONLY if authorized... } }
How the Zero-Trust Fail-Closed Flow Works:
- Auto-Discovery via
debug_backtrace: WhenAclRegistry::protect()is called for the first time, it captures the calling class, method, and source file. - Instant Fail-Closed (HTTP 403 for EVERYONE):
- If the resource has not yet been configured in the database, it is automatically created with
is_unconfigured = true. - Access is strictly blocked with HTTP 403 Forbidden for all users, EVEN Super Admin with
all_access = true. - No sensitive code can ever execute accidentally without explicit authorization rules in place.
- If the resource has not yet been configured in the database, it is automatically created with
- Admin Panel Notification:
- An alert banner immediately appears on the Custom Resources page (
/acl-admin/resources), indicating how many auto-discovered resources are awaiting configuration. - Filter by status
๐ Awaiting Configuration (Blocked)to locate them.
- An alert banner immediately appears on the Custom Resources page (
- Configuration & Unlocking:
- When an administrator assigns permissions (or marks the resource as public or super-admin only) and clicks Save,
is_unconfiguredis set tofalse. - The ACL cache is instantly refreshed, unlocking normal access for authorized users.
- When an administrator assigns permissions (or marks the resource as public or super-admin only) and clicks Save,
๐๏ธ 5 Explicit Visual Access Policies (Zero Ambiguity)
In previous systems, removing all permissions from a protected route or resource would subtly default to open access for any authenticated user while still displaying a generic "Protected" badge. Role Permission Manager resolves this with 5 distinct, visually unequivocal access policies:
| Policy | Visual Badge | Behavior |
|---|---|---|
| ๐ Pubblica | badge-public (Green) |
Accessible to anyone on the internet without login. |
| ๐ค Solo Autenticati | badge-authenticated (Purple) |
Requires authentication only; open to all logged-in users regardless of role or permissions. |
| ๐ก๏ธ Con Permessi Specifici | badge-protected (Blue) |
Requires login and matching granular permissions (OR / AND operator). |
| ๐ Solo Super Admin | badge-superadmin (Gold) |
Reserved exclusively for Super Admin role (HTTP 403 for everyone else). |
| ๐ Bloccata / Da Configurare | badge-unconfigured (Red) |
Fail-Closed lockout. HTTP 403 Forbidden for everyone, including Super Admin. |
One-Click Instant Locking (๐ Blocca subito)
In the edit screen of any HTTP route or custom resource, administrators can click the dedicated ๐ Blocca (Fail-Closed) button to immediately sever access to any endpoint without deleting its configuration.
Bulk Policy Operations
From both the HTTP Routes and Custom Resources tables, select multiple items and apply:
๐ Blocca Selezionate (In attesa di configurazione): Instantly setsis_unconfigured = truein bulk.๐ค Imposta "Solo Autenticati": Clears permissions and marks resources as accessible to any authenticated user in bulk.
๐ฏ Granular Route Parameter Rules (URI Placeholders)
Secure dynamic route parameters without writing custom controller logic or custom regex middleware. For example, on a route like /server-reports/{page}/{destination}:
- Automatic Placeholder Detection:
- In
/acl-admin/routes/{id}/edit, the system automatically parses and displays badges for all URI placeholders (e.g.{page},{destination}).
- In
- Per-Value Authorization:
- Define granular permission rules for specific parameter values:
page = financialโ Requiresreports.view_financialpage = auditsโ Requiresreports.view_audits(or Super Admin only)page = overviewโ Mark as public access
- Define granular permission rules for specific parameter values:
- Unmatched Parameter Policy (Fallback):
- Choose how the system reacts when a user requests an unlisted parameter value (e.g.
/server-reports/malicious_page/1):- 404 Not Found (
deny_404): Blocks probe attempts early before hitting your controller. - 403 Forbidden (
deny_403): Rejects unauthorized values. - Pass-through (
allow): Passes unlisted values to your controller.
- 404 Not Found (
- Choose how the system reacts when a user requests an unlisted parameter value (e.g.
- Zero Performance Overhead:
- Parameter rules are compiled directly into the cached resources map and evaluated in-memory by
DynamicAclGuard.
- Parameter rules are compiled directly into the cached resources map and evaluated in-memory by
โ๏ธ Configuration Reference
Key settings in config/rolepermissionmanager.php:
return [ // User Model & Search Configuration 'users' => [ 'table' => 'users', 'searchable_fields' => ['name', 'cognome', 'email'], // Single column or array of columns concatenated with space: 'display_field' => ['name', 'cognome'], // e.g. "Mario Rossi" 'secondary_field' => ['matricola', 'email'], // e.g. "MAT12345 mario@company.it" 'per_page' => 25, ], // Super Admin Settings & Bypass 'super_admin' => [ 'role' => 'super-admin', // Role slug or null to disable 'all_access' => true, // true / 'all' for full bypass, false/null to require explicit permissions ], // Middleware settings 'middleware' => [ 'register_globally' => true, // Applied to 'web' and 'api' groups 'guard' => null, // null = default guard 'unprotected_behavior' => 'allow', // 'allow' or 'deny' ], // Automated Scheduler 'scheduler' => [ 'enabled' => false, 'time' => '06:00', 'options' => [ 'clean' => false, 'auto_permissions' => false, 'notify' => true, ], ], // Web Admin Panel 'admin_panel' => [ 'enabled' => true, 'prefix' => 'acl-admin', 'middleware' => ['web', 'auth'], 'page_title' => 'ACL Manager', 'per_page' => 25, ], ];
๐งช Testing & Standalone Preview
Run the test suite:
composer test # or ./vendor/bin/phpunit
Standalone Workbench Preview (No full app required!)
# 1. Run migrations and seed demo data php vendor/bin/testbench migrate:fresh --seed --class="Workbench\Database\Seeders\DatabaseSeeder" # 2. Start the local server php vendor/bin/testbench serve --port=8080
Open http://127.0.0.1:8080 and log in with:
- Email:
admin@demo.test - Password:
password
๐ License
The MIT License (MIT). Please see LICENSE for more information.