ubxty / multi-tenant-laravel-permissions
A powerful, multi-tenant capable permission handling package for Laravel with role-based access control, wildcard permissions, and high-performance caching.
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/ubxty/multi-tenant-laravel-permissions
Requires
- php: ^8.2
- illuminate/auth: ^10.0|^11.0|^12.0
- illuminate/cache: ^10.0|^11.0|^12.0
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/database: ^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.5|^11.0
README
A powerful, multi-tenant capable permission handling package for Laravel with role-based access control, wildcard permissions, and high-performance caching.
Built by Ubxty
Features
- 🏢 Multi-Tenancy Support - Tenant-scoped roles and permissions out of the box
- 🔑 UUID Support - First-class UUID support for roles and permissions
- ⚡ High-Performance Caching - In-memory + database JSON caching for minimal DB queries
- 🃏 Wildcard Permissions - Grant access to permission groups with
posts.* - 🎛️ Permission Scopes - Attach JSON settings/constraints to permissions per role
- 🛡️ Middleware - Ready-to-use permission and role middleware
- 🎨 Blade Directives - Convenient
@role,@hasrole,@hasanyrole,@hasallroles,@unlessrole - 📦 Laravel 10, 11 & 12 - Full support for modern Laravel versions
Requirements
- PHP 8.2+
- Laravel 10.x, 11.x, or 12.x
Installation
Install the package via Composer:
composer require ubxty/multi-tenant-laravel-permissions
Publish the configuration and migrations:
php artisan vendor:publish --provider="Ubxty\MultiTenantLaravelPermissions\MultiTenantPermissionsServiceProvider"
Run the migrations:
php artisan migrate
Setup
1. User Model
Add the HasRoles trait to your User model:
namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Ubxty\MultiTenantLaravelPermissions\Traits\HasRoles; class User extends Authenticatable { use HasRoles; }
2. Custom Models (Optional)
Extend the package models for custom logic:
// App\Models\Role.php namespace App\Models; use Ubxty\MultiTenantLaravelPermissions\Models\Role as BaseRole; class Role extends BaseRole { // Your custom logic }
Update your config to use custom models:
// config/multi-tenant-permissions.php 'models' => [ 'permission' => App\Models\Permission::class, 'role' => App\Models\Role::class, ],
Usage
Creating Roles & Permissions
use App\Models\Role; use App\Models\Permission; // Create a Permission $permission = Permission::create(['name' => 'edit articles']); // Create a Role (with optional tenant_id for multi-tenancy) $role = Role::create([ 'name' => 'writer', 'title' => 'Content Writer', 'tenant_id' => 1 ]); // Assign Permission to Role $role->givePermissionTo($permission);
Assigning Roles to Users
$user = User::find(1); // Assign a role $user->assignRole('writer'); // Assign multiple roles $user->assignRole('writer', 'editor'); // Sync roles (replaces current roles) $user->syncRoles(['writer', 'admin']);
Checking Permissions
// Check if user has a specific permission (direct or via role) if ($user->hasPermissionTo('edit articles')) { // ... } // Check if user has a role if ($user->hasRole('writer')) { // ... } // Check for any role if ($user->hasAnyRole(['writer', 'editor'])) { // ... }
Blade Directives
@role('admin') <p>Welcome, Admin!</p> @endrole @hasanyrole('writer|editor') <p>You can write or edit content.</p> @endhasanyrole @hasallroles('writer|editor') <p>You are both a writer and an editor!</p> @endhasallroles @unlessrole('admin') <p>You are not an admin.</p> @endunlessrole
Laravel's native @can directive also works seamlessly:
@can('edit articles') <button>Edit Article</button> @endcan
Multi-Tenancy
This package supports multi-tenancy out of the box. Roles and permissions can be scoped to a specific tenant.
Configuration
// config/multi-tenant-permissions.php 'column_names' => [ 'tenant_column_name' => 'tenant_id', // or 'organization_id', 'team_id', 'workspace_id', etc. ],
Tenant-Scoped Methods
// Check if user has a role for a specific tenant if ($user->hasRoleForTenant('admin', $tenantId)) { // ... } // Assign a role for a specific tenant $user->assignRoleForTenant('manager', $tenantId); // Get all roles for a specific tenant $roles = $user->getRolesForTenant($tenantId); // Sync roles for a specific tenant $user->syncRolesForTenant(['editor', 'writer'], $tenantId); // Check if user has a permission for a specific tenant if ($user->hasPermissionForTenant('edit posts', $tenantId)) { // ... }
High-Performance Caching
This package implements a dual-layer caching system for optimal performance:
- Database JSON Cache: Permissions and roles are cached as JSON in columns on the users table
- In-Memory Cache: Parsed once per request, all subsequent checks use RAM
Setup
Add cache columns to your users table:
Schema::table('users', function (Blueprint $table) { $table->json('permissions_cache')->nullable(); $table->json('roles_cache')->nullable(); });
Performance Impact
| Scenario | Without Cache | With Cache |
|---|---|---|
| Dashboard with 20 permission checks | 20+ DB queries | 1 DB query |
| Kanban board with 50 items | 50+ DB queries | 1 DB query |
Wildcard Permissions
Grant access to a group of permissions with wildcards:
// Create specific permissions Permission::create(['name' => 'posts.create']); Permission::create(['name' => 'posts.edit']); Permission::create(['name' => 'posts.delete']); // Create wildcard permission $wildcard = Permission::create(['name' => 'posts.*']); // Assign wildcard - grants access to all posts.* permissions $user->givePermissionTo($wildcard); $user->can('posts.create'); // true $user->can('posts.edit'); // true $user->can('posts.delete'); // true
Permission Settings & Scopes
Attach JSON settings to permissions when assigning to roles:
$role = Role::findByName('manager'); // Grant permission with specific scope settings $role->givePermissionToWithSettings('view_projects', [ 'scope' => 'team_only', 'limit' => 10 ]); // Update settings $role->updatePermissionSettings('view_projects', [ 'scope' => 'global' ]); // Retrieve settings $settings = $role->getPermissionSettings('view_projects');
Middleware
Register Middleware
In Laravel 11+, add to your bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'role' => \Ubxty\MultiTenantLaravelPermissions\Middleware\RoleMiddleware::class, 'permission' => \Ubxty\MultiTenantLaravelPermissions\Middleware\PermissionMiddleware::class, 'role_or_permission' => \Ubxty\MultiTenantLaravelPermissions\Middleware\RoleOrPermissionMiddleware::class, ]); })
Usage
Route::group(['middleware' => ['role:admin']], function () { // Admin only routes }); Route::group(['middleware' => ['permission:edit posts']], function () { // Users with 'edit posts' permission }); Route::group(['middleware' => ['role_or_permission:admin|edit posts']], function () { // Users with admin role OR 'edit posts' permission });
Commands
Clear the permission cache:
php artisan permission:cache-reset
Configuration
The config file allows customization of:
- Models: Custom Role and Permission classes
- Table Names: Custom database table names
- Column Names: Custom pivot keys, tenant column, cache columns
- Cache Settings: Expiration time, cache key, cache store
See the published config/multi-tenant-permissions.php for all options.
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email info@ubxty.com or open an issue on GitHub.
Credits
License
The MIT License (MIT). Please see License File for more information.