PHPackages                             litepie/shield - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. litepie/shield

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

litepie/shield
==============

A production-ready Laravel role and permission-based access control system

v1.0.1(8mo ago)012MITPHPPHP ^8.2

Since Aug 23Pushed 8mo agoCompare

[ Source](https://github.com/Litepie/Shield)[ Packagist](https://packagist.org/packages/litepie/shield)[ RSS](/packages/litepie-shield/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (9)Versions (3)Used By (0)

Litepie Shield - Laravel Role and Permission System
===================================================

[](#litepie-shield---laravel-role-and-permission-system)

A production-ready Laravel package for role and permission-based access control, built from scratch with all the features from Spatie's Laravel Permission package and enhanced with additional capabilities.

✨ Features
----------

[](#-features)

- **🔐 Roles and Permissions**: Comprehensive role-based access control system
- **🛡️ Multiple Guards**: Support for multiple authentication guards (web, api, custom)
- **🏢 Multi-Tenant Ready**: Complete tenant/organization isolation with dynamic context switching
- **🌟 Wildcard Permissions**: Hierarchical permissions with pattern matching (`posts.*`, `admin.*`)
- **⚡ High Performance Caching**: Redis/file-based caching with automatic invalidation
- **🎨 Blade Directives**: Beautiful template permission checking (`@role`, `@permission`)
- **🚧 Middleware Protection**: Route-level security with flexible middleware
- **📡 Event System**: Listen to permission/role changes with Laravel events
- **🔑 Passport Integration**: Full support for API authentication and machine-to-machine tokens
- **⚙️ Artisan Commands**: Complete CLI management for roles, permissions, and users
- **🚀 Laravel Octane Ready**: Optimized for high-performance Laravel Octane deployments
- **📊 Database Query Scopes**: Elegant Eloquent scopes for complex queries
- **🧪 Fully Tested**: Comprehensive test suite for production reliability

📋 Table of Contents
-------------------

[](#-table-of-contents)

- [Installation](#installation)
- [Quick Setup](#quick-setup)
- [Configuration](#configuration)
- [Basic Usage](#basic-usage)
- [Advanced Features](#advanced-features)
- [Multi-Tenant Support](#multi-tenant-support)
- [Wildcard Permissions](#wildcard-permissions)
- [Middleware](#middleware)
- [Blade Directives](#blade-directives)
- [Database Queries](#database-queries)
- [Events](#events)
- [API Integration](#api-integration)
- [Performance &amp; Caching](#performance--caching)
- [Artisan Commands](#artisan-commands)
- [Testing](#testing)
- [Migration from Spatie](#migration-from-spatie)
- [Contributing](#contributing)

🚀 Installation
--------------

[](#-installation)

**Requirements:**

- PHP 8.2 or higher
- Laravel 10.x, 11.x, or 12.x

```
composer require litepie/shield
```

Publish the migration and config file:

```
php artisan vendor:publish --provider="Litepie\Shield\ShieldServiceProvider"
```

Run the migrations:

```
php artisan migrate
```

Quick Setup
-----------

[](#quick-setup)

### Create Super User

[](#create-super-user)

After installation, create a super user with full admin privileges:

```
php artisan shield:create-superuser
```

This command will:

- Create a "Super Admin" role with all permissions
- Create comprehensive permissions for your application
- Create a user account and assign the Super Admin role
- Provide you with login credentials

You can also run it non-interactively:

```
php artisan shield:create-superuser --name="Administrator" --email="admin@yourdomain.com" --password="secure-password"
```

⚙️ Configuration
----------------

[](#️-configuration)

The configuration file `config/shield.php` provides extensive customization options:

```
return [
    'models' => [
        'permission' => Litepie\Shield\Models\Permission::class,
        'role' => Litepie\Shield\Models\Role::class,
    ],

    'table_names' => [
        'roles' => 'roles',
        'permissions' => 'permissions',
        'model_has_permissions' => 'model_has_permissions',
        'model_has_roles' => 'model_has_roles',
        'role_has_permissions' => 'role_has_permissions',
    ],

    'cache' => [
        'expiration_time' => \DateInterval::createFromDateString('24 hours'),
        'key' => 'shield.cache',
        'store' => 'default',
    ],

    'tenants' => false, // Enable for multi-tenant applications
    'use_passport_client_credentials' => false, // Enable for API authentication
    'enable_wildcard_permission' => false, // Enable hierarchical permissions
    'events_enabled' => false, // Enable role/permission events
];
```

### Configuration Options Explained

[](#configuration-options-explained)

OptionDescriptionDefault`models.permission`Permission model class`Litepie\Shield\Models\Permission``models.role`Role model class`Litepie\Shield\Models\Role``table_names.*`Database table namesStandard naming`cache.expiration_time`Cache duration24 hours`cache.store`Cache store to use`default``tenants`Enable multi-tenant support`false``use_passport_client_credentials`API authentication`false``enable_wildcard_permission`Hierarchical permissions`false``events_enabled`Event firing`false`📚 Basic Usage
-------------

[](#-basic-usage)

### Setting up Models

[](#setting-up-models)

Add the `HasRoles` trait to your User model:

```
use Litepie\Shield\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;

    // ...
}
```

For models that only need permissions (not roles), use `HasPermissions`:

```
use Litepie\Shield\Traits\HasPermissions;

class ApiClient extends Model
{
    use HasPermissions;
}
```

### Creating Roles and Permissions

[](#creating-roles-and-permissions)

#### Basic Creation

[](#basic-creation)

```
use Litepie\Shield\Models\Role;
use Litepie\Shield\Models\Permission;

// Create permissions
$permission = Permission::create(['name' => 'edit articles']);
$deletePermission = Permission::create(['name' => 'delete articles']);

// Create roles
$writerRole = Role::create(['name' => 'writer']);
$editorRole = Role::create(['name' => 'editor']);

// Assign permissions to roles
$writerRole->givePermissionTo('edit articles');
$editorRole->givePermissionTo(['edit articles', 'delete articles']);

// Or using the permission object
$writerRole->givePermissionTo($permission);
```

#### Advanced Creation with Guards

[](#advanced-creation-with-guards)

```
// Create for specific guard
$apiPermission = Permission::create([
    'name' => 'access-api',
    'guard_name' => 'api'
]);

$adminRole = Role::create([
    'name' => 'admin',
    'guard_name' => 'web'
]);

// Create with additional attributes
$moderatorRole = Role::create([
    'name' => 'moderator',
    'guard_name' => 'web',
    'description' => 'Content moderation role',
    'level' => 5
]);
```

### Assigning Roles and Permissions

[](#assigning-roles-and-permissions)

#### Role Assignment

[](#role-assignment)

```
// Assign single role
$user->assignRole('writer');
$user->assignRole($writerRole);

// Assign multiple roles
$user->assignRole(['writer', 'editor']);
$user->assignRole([$writerRole, $editorRole]);

// Sync roles (removes all other roles)
$user->syncRoles(['admin', 'editor']);

// Remove roles
$user->removeRole('writer');
$user->removeRole(['writer', 'editor']);
```

#### Direct Permission Assignment

[](#direct-permission-assignment)

```
// Give permission directly to user
$user->givePermissionTo('edit articles');
$user->givePermissionTo(['edit articles', 'delete articles']);

// Using permission object
$user->givePermissionTo($permission);

// Sync permissions
$user->syncPermissions(['edit articles', 'view dashboard']);

// Revoke permissions
$user->revokePermissionTo('edit articles');
$user->revokePermissionTo(['edit articles', 'delete articles']);
```

### Checking Permissions and Roles

[](#checking-permissions-and-roles)

#### Permission Checks

[](#permission-checks)

```
// Laravel's built-in authorization
$user->can('edit articles');
$user->cannot('delete articles');

// Package-specific methods
$user->hasPermissionTo('edit articles');
$user->hasDirectPermission('edit articles'); // Only direct permissions
$user->hasPermissionViaRole('edit articles'); // Only via roles

// Check multiple permissions
$user->hasAnyPermission(['edit articles', 'delete articles']);
$user->hasAllPermissions(['edit articles', 'view dashboard']);
```

#### Role Checks

[](#role-checks)

```
// Check if user has role
$user->hasRole('writer');
$user->hasRole($writerRole);

// Check multiple roles
$user->hasAnyRole(['writer', 'editor']);
$user->hasAllRoles(['writer', 'editor']);
$user->hasExactRoles(['writer', 'editor']); // Only these roles, no more

// Get user roles
$roles = $user->roles; // Collection of roles
$roleNames = $user->getRoleNames(); // Collection of role names
```

#### Advanced Checks

[](#advanced-checks)

```
// Check with specific guard
$user->hasRole('admin', 'web');
$user->hasPermissionTo('access-api', 'api');

// Get permissions
$permissions = $user->permissions; // Direct permissions
$allPermissions = $user->getAllPermissions(); // Direct + via roles
$rolePermissions = $user->getPermissionsViaRoles(); // Only via roles

// Check if user has any permissions
if ($user->permissions->isNotEmpty()) {
    // User has some permissions
}
```

🚀 Advanced Features
-------------------

[](#-advanced-features)

### Custom Models

[](#custom-models)

Extend the base models to add your own functionality:

```
use Litepie\Shield\Models\Permission as ShieldPermission;

class Permission extends ShieldPermission
{
    protected $fillable = ['name', 'guard_name', 'description', 'category'];

    public function category()
    {
        return $this->belongsTo(PermissionCategory::class);
    }

    public function scopeByCategory($query, $category)
    {
        return $query->where('category', $category);
    }
}
```

Update your config:

```
'models' => [
    'permission' => App\Models\Permission::class,
    'role' => App\Models\Role::class,
],
```

### Multiple Guards

[](#multiple-guards)

Shield supports multiple authentication guards seamlessly:

```
// Web guard (default)
$webRole = Role::create(['name' => 'admin', 'guard_name' => 'web']);
$user->assignRole($webRole);

// API guard
$apiRole = Role::create(['name' => 'api-admin', 'guard_name' => 'api']);
$apiUser->assignRole($apiRole);

// Custom guard
$customRole = Role::create(['name' => 'manager', 'guard_name' => 'custom']);

// Check permissions with specific guard
$user->hasPermissionTo('edit posts', 'web');
$apiUser->hasPermissionTo('access api', 'api');
```

### Permission Inheritance

[](#permission-inheritance)

Create hierarchical permission structures:

```
// Parent permissions
Permission::create(['name' => 'posts']);
Permission::create(['name' => 'posts.view']);
Permission::create(['name' => 'posts.create']);
Permission::create(['name' => 'posts.edit']);
Permission::create(['name' => 'posts.delete']);

// With wildcard enabled, granting 'posts.*' gives all post permissions
$user->givePermissionTo('posts.*');

$user->can('posts.view'); // true
$user->can('posts.edit'); // true
$user->can('posts.delete'); // true
```

🏢 Multi-Tenant Support
----------------------

[](#-multi-tenant-support)

Shield provides complete multi-tenant isolation with tenant-based permissions.

### Enable Tenants

[](#enable-tenants)

```
// config/shield.php
'tenants' => true,
'column_names' => [
    'tenant_foreign_key' => 'tenant_id',
],
```

### Tenant Context Management

[](#tenant-context-management)

```
// Set tenant context globally
setPermissionsTenantId(1);

// Now all permission checks are scoped to tenant 1
$user->hasPermissionTo('edit articles'); // Only tenant 1 permissions
$user->can('manage users'); // Scoped to tenant 1

// Get current tenant
$tenantId = getPermissionsTenantId(); // Returns: 1

// Switch tenants dynamically
setPermissionsTenantId(2);
$user->can('edit posts'); // Now checks tenant 2 permissions
```

### Tenant-Specific Operations

[](#tenant-specific-operations)

```
// Create tenant-specific roles and permissions
$tenantRole = Role::create([
    'name' => 'Tenant Manager',
    'guard_name' => 'web',
    'tenant_id' => 1
]);

$tenantPermission = Permission::create([
    'name' => 'manage tenant members',
    'guard_name' => 'web',
    'tenant_id' => 1
]);

// Assign with tenant context
setPermissionsTenantId(1);
$user->assignRole('Tenant Manager');
$user->givePermissionTo('manage tenant members');
```

### Custom Tenant Resolver

[](#custom-tenant-resolver)

Implement automatic tenant detection:

```
use Litepie\Shield\Contracts\PermissionsTenantResolver;

class CustomTenantResolver implements PermissionsTenantResolver
{
    public function getPermissionsTenantId(): ?int
    {
        // Get from authenticated user
        return auth()->user()?->current_tenant_id;

        // Or from request header
        return request()->header('X-Tenant-ID');

        // Or from subdomain
        $subdomain = request()->getHost();
        return Tenant::where('subdomain', $subdomain)->value('id');
    }

    public function setPermissionsTenantId(?int $tenantId): void
    {
        if ($user = auth()->user()) {
            $user->update(['current_tenant_id' => $tenantId]);
        }

        session(['current_tenant_id' => $tenantId]);
    }
}
```

Register in `AppServiceProvider`:

```
$this->app->bind(PermissionsTenantResolver::class, CustomTenantResolver::class);
```

### Multi-Tenant Middleware

[](#multi-tenant-middleware)

```
class SetTenantContext
{
    public function handle($request, Closure $next)
    {
        // Extract tenant from subdomain
        $host = $request->getHost();
        $subdomain = explode('.', $host)[0];

        $tenant = Tenant::where('subdomain', $subdomain)->first();

        if ($tenant) {
            setPermissionsTenantId($tenant->id);
            app()->instance('current_tenant', $tenant);
        }

        return $next($request);
    }
}
```

⭐ Wildcard Permissions
----------------------

[](#-wildcard-permissions)

Register the middleware in your `Kernel.php`:

```
protected $routeMiddleware = [
    // ...
    'role' => \Litepie\Shield\Middleware\RoleMiddleware::class,
    'permission' => \Litepie\Shield\Middleware\PermissionMiddleware::class,
    'role_or_permission' => \Litepie\Shield\Middleware\RoleOrPermissionMiddleware::class,
];
```

```
// Role-based protection
Route::group(['middleware' => ['role:admin']], function () {
    Route::get('/admin/dashboard', [AdminController::class, 'dashboard']);
    Route::resource('/admin/users', UserController::class);
});

// Permission-based protection
Route::group(['middleware' => ['permission:edit articles']], function () {
    Route::put('/articles/{article}', [ArticleController::class, 'update']);
    Route::delete('/articles/{article}', [ArticleController::class, 'destroy']);
});

// Multiple permissions (user needs ALL)
Route::group(['middleware' => ['permission:edit articles,publish articles']], function () {
    Route::post('/articles/{article}/publish', [ArticleController::class, 'publish']);
});

// Multiple permissions (user needs ANY)
Route::group(['middleware' => ['role_or_permission:admin|edit articles']], function () {
    Route::get('/articles/{article}/edit', [ArticleController::class, 'edit']);
});
```

### Advanced Middleware Usage

[](#advanced-middleware-usage)

```
// Multiple roles (user needs ANY)
Route::middleware('role:admin|editor|author')->group(function () {
    Route::get('/content', [ContentController::class, 'index']);
});

// Specific guard
Route::middleware('role:api-admin,api')->group(function () {
    Route::apiResource('/api/users', ApiUserController::class);
});

// Combined with other middleware
Route::middleware(['auth', 'verified', 'role:admin'])->group(function () {
    Route::get('/admin/settings', [SettingsController::class, 'index']);
});

// Using route macros (more elegant)
Route::role('admin')->group(function () {
    Route::get('/admin/dashboard', [AdminController::class, 'dashboard']);
});

Route::permission('manage content')->group(function () {
    Route::resource('/content', ContentController::class);
});
```

### Custom Middleware

[](#custom-middleware)

Create your own permission middleware:

```
class RequirePermissionMiddleware
{
    public function handle($request, Closure $next, $permission, $guard = null)
    {
        $user = Auth::guard($guard)->user();

        if (!$user || !$user->can($permission)) {
            if ($request->expectsJson()) {
                return response()->json(['error' => 'Forbidden'], 403);
            }

            abort(403, 'You do not have permission to access this resource.');
        }

        return $next($request);
    }
}
```

🎨 Blade Directives
------------------

[](#-blade-directives)

Beautiful template-level permission checking.

### Role Directives

[](#role-directives)

```
@role('admin')

        Admin Panel
        Welcome to the admin dashboard!

@endrole

@hasrole('editor')
    Edit Content
@endhasrole

@hasanyrole(['admin', 'editor', 'author'])

        Content Tools

@endhasanyrole

@hasallroles(['admin', 'supervisor'])
    Critical Action
@endhasallroles

@hasexactroles(['editor'])
    You are an editor (and nothing else)
@endhasexactroles
```

### Permission Directives

[](#permission-directives)

```
@permission('edit articles')

        Edit Article

@endpermission

@haspermission('delete articles')

        @csrf @method('DELETE')
        Delete

@endhaspermission

@hasanypermission(['edit articles', 'publish articles'])

@endhasanypermission
```

### Advanced Blade Usage

[](#advanced-blade-usage)

```

@auth
    @role('admin')
        Admin Dashboard
    @endrole

    @permission('view reports')
        Reports
    @endpermission
@endauth

@role('manager')

        @permission('approve requests')
            Approve
        @endpermission

        @permission('reject requests')
            Reject
        @endpermission

@endrole

@hasrole($requiredRole)
    You have the required role: {{ $requiredRole }}
@endhasrole

@role('admin', 'web')
    Web admin access
@endrole
```

🗃️ Database Queries
-------------------

[](#️-database-queries)

Powerful Eloquent scopes for complex permission queries.

### User Queries

[](#user-queries)

### Tenants Feature

[](#tenants-feature)

Enable tenants in config:

```
'tenants' => true,
```

Set the tenant context:

```
// Set tenant context
setPermissionsTenantId(1);

// Now all permission checks will be scoped to tenant 1
$user->hasPermissionTo('edit articles'); // Only checks tenant 1 permissions

// Get current tenant
$tenantId = getPermissionsTenantId();
```

Create hierarchical permissions with pattern matching:

### Enable Wildcards

[](#enable-wildcards)

```
// config/shield.php
'enable_wildcard_permission' => true,
```

### Wildcard Patterns

[](#wildcard-patterns)

```
// Grant broad permissions with wildcards
$user->givePermissionTo('posts.*');

// This automatically grants:
$user->can('posts.create'); // true
$user->can('posts.edit');   // true
$user->can('posts.delete'); // true
$user->can('posts.view');   // true
$user->can('posts.publish'); // true

// But not:
$user->can('comments.create'); // false
$user->can('users.edit'); // false

// Multi-level wildcards
$user->givePermissionTo('admin.*');
$user->can('admin.users.create'); // true
$user->can('admin.settings.edit'); // true
$user->can('admin.reports.view'); // true

// Specific patterns
$user->givePermissionTo('posts.*.own');
$user->can('posts.edit.own'); // true
$user->can('posts.delete.own'); // true
$user->can('posts.edit.any'); // false
```

### Wildcard Examples

[](#wildcard-examples)

```
// Content management
$editor->givePermissionTo('content.*');
// Grants: content.posts.*, content.pages.*, content.media.*

// User administration
$admin->givePermissionTo('users.*');
// Grants: users.view, users.create, users.edit, users.delete

// API access levels
$apiUser->givePermissionTo('api.v1.*');
// Grants: api.v1.users, api.v1.posts, api.v1.analytics

// Department-specific access
$manager->givePermissionTo('department.sales.*');
// Grants: department.sales.reports, department.sales.leads, etc.
```

🚧 Middleware
------------

[](#-middleware)

Protect your routes with flexible middleware options.

### Register Middleware

[](#register-middleware)

Add to `app/Http/Kernel.php`:

```
protected $routeMiddleware = [
    // ...
    'role' => \Litepie\Shield\Middleware\RoleMiddleware::class,
    'permission' => \Litepie\Shield\Middleware\PermissionMiddleware::class,
    'role_or_permission' => \Litepie\Shield\Middleware\RoleOrPermissionMiddleware::class,
];
```

### Basic Usage

[](#basic-usage)

```
Complete CLI management for your permission system.

### Basic Commands

```bash
# Create permission
php artisan shield:create-permission "edit articles"
php artisan shield:create-permission "manage users" --guard=web

# Create role
php artisan shield:create-role writer
php artisan shield:create-role "content manager" --guard=web

# Create super user with full admin access
php artisan shield:create-superuser

# Interactive mode (prompts for details)
php artisan shield:create-superuser

# Non-interactive mode
php artisan shield:create-superuser
  --name="Site Administrator"
  --email="admin@yoursite.com"
  --password="secure-password-123"

# Clear permission cache
php artisan shield:cache-reset
```

### Tenant-Specific Commands

[](#tenant-specific-commands)

```
# Create tenant-specific permission
php artisan shield:create-permission "manage inventory" --tenantId=1

# Create tenant-specific role
php artisan shield:create-role "warehouse manager" --tenantId=1

# Create superuser for specific tenant
php artisan shield:create-superuser --tenantId=1
```

### Advanced Management

[](#advanced-management)

```
# Show all roles and permissions
php artisan shield:show

# Upgrade database for tenants feature
php artisan shield:upgrade-for-tenants

# Custom commands you can create
php artisan make:command AssignBulkPermissions
php artisan make:command SyncUserRoles
php artisan make:command AuditPermissions
```

🧪 Testing
---------

[](#-testing)

Comprehensive testing helpers for your application tests.

### Test Helpers

[](#test-helpers)

```
use Litepie\Shield\Models\Role;
use Litepie\Shield\Models\Permission;

class UserPermissionTest extends TestCase
{
    /** @test */
    public function user_can_edit_articles_with_permission()
    {
        // Create user with permission
        $user = User::factory()->create();
        $permission = Permission::create(['name' => 'edit articles']);
        $user->givePermissionTo($permission);

        // Test permission
        $this->assertTrue($user->can('edit articles'));

        // Test via HTTP
        $this->actingAs($user)
            ->get('/articles/1/edit')
            ->assertStatus(200);
    }

    /** @test */
    public function user_can_access_admin_with_role()
    {
        $user = User::factory()->create();
        $role = Role::create(['name' => 'admin']);
        $user->assignRole($role);

        $this->assertTrue($user->hasRole('admin'));

        $this->actingAs($user)
            ->get('/admin/dashboard')
            ->assertStatus(200);
    }
}
```

### Testing Multi-Tenant

[](#testing-multi-tenant)

```
/** @test */
public function permissions_are_isolated_by_tenant()
{
    $user = User::factory()->create();

    // Tenant 1 permission
    setPermissionsTenantId(1);
    $user->givePermissionTo('edit posts');

    // Tenant 2 permission
    setPermissionsTenantId(2);
    $user->givePermissionTo('delete posts');

    // Test tenant 1 context
    setPermissionsTenantId(1);
    $this->assertTrue($user->can('edit posts'));
    $this->assertFalse($user->can('delete posts'));

    // Test tenant 2 context
    setPermissionsTenantId(2);
    $this->assertFalse($user->can('edit posts'));
    $this->assertTrue($user->can('delete posts'));
}
```

### Testing Middleware

[](#testing-middleware)

```
/** @test */
public function middleware_blocks_unauthorized_access()
{
    $user = User::factory()->create();

    // Without permission
    $this->actingAs($user)
        ->get('/admin/users')
        ->assertStatus(403);

    // With permission
    $user->givePermissionTo('manage users');
    $this->actingAs($user)
        ->get('/admin/users')
        ->assertStatus(200);
}
```

### Performance Testing

[](#performance-testing)

```
/** @test */
public function permission_checks_are_cached()
{
    $user = User::factory()->create();
    $user->givePermissionTo('test permission');

    // First check (loads from database)
    $start = microtime(true);
    $user->can('test permission');
    $firstCheckTime = microtime(true) - $start;

    // Second check (loads from cache)
    $start = microtime(true);
    $user->can('test permission');
    $secondCheckTime = microtime(true) - $start;

    // Cache should be significantly faster
    $this->assertLessThan($firstCheckTime / 2, $secondCheckTime);
}
```

🔄 Migration from Spatie
-----------------------

[](#-migration-from-spatie)

Easy migration path from Spatie Laravel Permission.

### Migration Script

[](#migration-script)

```
// Create a migration command
php artisan make:command MigrateFromSpatie

class MigrateFromSpatie extends Command
{
    protected $signature = 'shield:migrate-from-spatie';
    protected $description = 'Migrate from Spatie Laravel Permission to Litepie Shield';

    public function handle()
    {
        $this->info('Migrating from Spatie to Litepie Shield...');

        // Update namespace references
        $this->updateModelReferences();

        // Update config references
        $this->updateConfigReferences();

        // Update database references if needed
        $this->updateDatabaseReferences();

        $this->info('Migration completed successfully!');
    }

    protected function updateModelReferences()
    {
        // Replace Spatie namespace with Litepie
        $files = [
            'app/Models/User.php',
            'config/permission.php',
            // Add other files as needed
        ];

        foreach ($files as $file) {
            if (File::exists($file)) {
                $content = File::get($file);
                $content = str_replace(
                    'Spatie\Permission',
                    'Litepie\Shield',
                    $content
                );
                File::put($file, $content);
            }
        }
    }
}
```

### Key Differences

[](#key-differences)

FeatureSpatieLitepie ShieldNamespace`Spatie\Permission``Litepie\Shield`Config file`permission.php``shield.php`Service Provider`PermissionServiceProvider``ShieldServiceProvider`Cache key`spatie.permission.cache``shield.cache`Tenants config`enable_tenants``tenants`### Update Steps

[](#update-steps)

1. **Install Shield**: `composer require litepie/shield`
2. **Update config**: Rename and update configuration
3. **Update models**: Change namespace references
4. **Update middleware**: Register new middleware classes
5. **Test thoroughly**: Ensure all permissions work correctly

🤝 Contributing
--------------

[](#-contributing)

We welcome contributions! Please see our contributing guidelines.

### Development Setup

[](#development-setup)

```
# Clone the repository
git clone https://github.com/litepie/shield.git
cd shield

# Install dependencies
composer install

# Run tests
composer test

# Run code analysis
composer analyse

# Run code formatting
composer format
```

### Running Tests

[](#running-tests)

```
# Run all tests
composer test

# Run specific test
./vendor/bin/phpunit tests/PermissionTest.php

# Run with coverage
composer test-coverage
```

### Code Standards

[](#code-standards)

- Follow PSR-12 coding standards
- Add tests for new features
- Update documentation
- Use semantic versioning

📝 License
---------

[](#-license)

```

```php
// Users with specific role
$admins = User::role('admin')->get();
$editors = User::role(['editor', 'author'])->get();

// Users with specific permission
$canEdit = User::permission('edit articles')->get();
$canPublish = User::permission(['publish articles', 'edit articles'])->get();

// Users without specific role
$nonAdmins = User::withoutRole('admin')->get();
$notManagement = User::withoutRole(['admin', 'manager'])->get();

// Users without specific permission
$cannotDelete = User::withoutPermission('delete articles')->get();

// Complex combinations
$contentTenants = User::role(['editor', 'author'])
    ->permission('edit articles')
    ->where('active', true)
    ->get();

// Users with any of the specified roles
$management = User::hasAnyRole(['admin', 'manager', 'supervisor'])->get();

// Users with all specified roles
$superUsers = User::hasAllRoles(['admin', 'superuser'])->get();

```

### Role and Permission Queries

[](#role-and-permission-queries)

```
// Roles with specific permissions
$rolesWithEditAccess = Role::whereHas('permissions', function ($query) {
    $query->where('name', 'edit articles');
})->get();

// Permissions belonging to specific roles
$adminPermissions = Permission::whereHas('roles', function ($query) {
    $query->where('name', 'admin');
})->get();

// Unused permissions
$unusedPermissions = Permission::doesntHave('roles')
    ->doesntHave('users')
    ->get();

// Most common roles
$popularRoles = Role::withCount('users')
    ->orderBy('users_count', 'desc')
    ->get();

// Tenant-specific queries (when tenants enabled)
setPermissionsTenantId(1);
$tenantRoles = Role::where('tenant_id', 1)->get();
$tenantPermissions = Permission::where('tenant_id', 1)->get();
```

### Advanced Queries

[](#advanced-queries)

```
// Users who can perform specific action
$usersWhoCanEdit = User::whereHas('roles.permissions', function ($query) {
    $query->where('name', 'edit articles');
})->orWhereHas('permissions', function ($query) {
    $query->where('name', 'edit articles');
})->get();

// Roles that grant specific permission
$rolesWithPermission = Role::whereHas('permissions', function ($query) {
    $query->where('name', 'like', 'admin.%');
})->get();

// Permission usage statistics
$permissionStats = Permission::withCount(['roles', 'users'])
    ->get()
    ->map(function ($permission) {
        return [
            'name' => $permission->name,
            'total_users' => $permission->users_count +
                $permission->roles->sum('users_count'),
            'direct_assignments' => $permission->users_count,
            'role_assignments' => $permission->roles_count,
        ];
    });
```

📡 Events
--------

[](#-events)

Listen to role and permission changes throughout your application.

### Enable Events

[](#enable-events)

```
// config/shield.php
'events_enabled' => true,
```

### Available Events

[](#available-events)

```
use Litepie\Shield\Events\RoleAttached;
use Litepie\Shield\Events\RoleDetached;
use Litepie\Shield\Events\PermissionAttached;
use Litepie\Shield\Events\PermissionDetached;
```

### Event Listeners

[](#event-listeners)

```
// In EventServiceProvider
protected $listen = [
    RoleAttached::class => [
        SendRoleAssignmentNotification::class,
        LogRoleChange::class,
        UpdateUserCache::class,
    ],

    RoleDetached::class => [
        SendRoleRemovalNotification::class,
        LogRoleChange::class,
    ],

    PermissionAttached::class => [
        LogPermissionChange::class,
        NotifySecurityTenant::class,
    ],

    PermissionDetached::class => [
        LogPermissionChange::class,
    ],
];
```

### Example Listeners

[](#example-listeners)

```
class SendRoleAssignmentNotification
{
    public function handle(RoleAttached $event)
    {
        $user = $event->model;
        $role = $event->role;

        // Send notification
        $user->notify(new RoleAssignedNotification($role));

        // Log the change
        Log::info("Role '{$role->name}' assigned to user {$user->id}");

        // Update external systems
        if ($role->name === 'admin') {
            ExternalApi::grantAdminAccess($user);
        }
    }
}

class LogPermissionChange
{
    public function handle($event)
    {
        $user = $event->model;
        $permission = $event->permission;
        $action = $event instanceof PermissionAttached ? 'granted' : 'revoked';

        Log::channel('security')->info("Permission '{$permission->name}' {$action} for user {$user->id}");

        // Store audit trail
        AuditLog::create([
            'user_id' => $user->id,
            'action' => "permission_{$action}",
            'details' => [
                'permission' => $permission->name,
                'guard' => $permission->guard_name,
                'timestamp' => now(),
            ],
        ]);
    }
}
```

### Real-time Updates

[](#real-time-updates)

```
// Broadcast role changes
class BroadcastRoleChange
{
    public function handle(RoleAttached $event)
    {
        broadcast(new UserRoleUpdated($event->model, $event->role));
    }
}

// WebSocket event
class UserRoleUpdated implements ShouldBroadcast
{
    public $user;
    public $role;

    public function __construct($user, $role)
    {
        $this->user = $user;
        $this->role = $role;
    }

    public function broadcastOn()
    {
        return new PrivateChannel("user.{$this->user->id}");
    }
}
```

🔌 API Integration
-----------------

[](#-api-integration)

Full support for API authentication and machine-to-machine communication.

### Passport Integration

[](#passport-integration)

Enable Passport client credentials:

```
// config/shield.php
'use_passport_client_credentials' => true,
```

### API Authentication

[](#api-authentication)

```
// routes/api.php
Route::middleware(['client', 'permission:api.access'])->group(function () {
    Route::get('/users', [ApiUserController::class, 'index']);
    Route::post('/users', [ApiUserController::class, 'store']);
});

Route::middleware(['client', 'role:api-admin'])->group(function () {
    Route::delete('/users/{user}', [ApiUserController::class, 'destroy']);
});
```

### Machine-to-Machine

[](#machine-to-machine)

```
// Create API client with permissions
$client = PassportClient::create([
    'name' => 'Analytics Service',
    'secret' => Str::random(40),
    'personal_access_client' => false,
    'password_client' => false,
    'revoked' => false,
]);

// Grant permissions to client
$client->givePermissionTo(['api.analytics.read', 'api.reports.create']);

// Client credentials request
$response = Http::asForm()->post('your-app.com/oauth/token', [
    'grant_type' => 'client_credentials',
    'client_id' => $client->id,
    'client_secret' => $client->secret,
    'scope' => 'api.analytics.read api.reports.create',
]);

$token = $response->json()['access_token'];

// Use token for API requests
$apiResponse = Http::withToken($token)
    ->get('your-app.com/api/analytics');
```

### API Controllers

[](#api-controllers)

```
class ApiUserController extends Controller
{
    public function index()
    {
        // Automatic permission checking via middleware
        return UserResource::collection(User::paginate());
    }

    public function store(Request $request)
    {
        $this->authorize('create', User::class);

        // Create user logic
        $user = User::create($request->validated());

        return new UserResource($user);
    }

    public function destroy(User $user)
    {
        // Check permissions programmatically
        if (!auth()->user()->can('delete users')) {
            return response()->json(['error' => 'Forbidden'], 403);
        }

        $user->delete();

        return response()->json(['message' => 'User deleted successfully']);
    }
}
```

⚡ Performance &amp; Caching
---------------------------

[](#-performance--caching)

Optimized for high-performance applications with intelligent caching.

### Cache Configuration

[](#cache-configuration)

```
// config/shield.php
'cache' => [
    'expiration_time' => \DateInterval::createFromDateString('24 hours'),
    'key' => 'shield.cache',
    'store' => 'redis', // Use Redis for better performance
],
```

### Cache Management

[](#cache-management)

```
// Clear all permission cache
app(\Litepie\Shield\PermissionRegistrar::class)->forgetCachedPermissions();

// Automatically cleared when:
// - Roles or permissions are created/updated/deleted
// - User roles are assigned/removed
// - User permissions are granted/revoked

// Manual cache operations
Cache::tags(['shield'])->flush(); // Clear all Shield cache
Cache::forget('shield.permissions'); // Clear specific cache key
```

### Performance Tips

[](#performance-tips)

```
// 1. Eager load relationships
$users = User::with(['roles', 'permissions'])->get();

// 2. Use specific permission checks
$user->hasDirectPermission('edit articles'); // Faster than checking via roles

// 3. Cache complex queries
$adminUsers = Cache::remember('admin_users', 3600, function () {
    return User::role('admin')->get();
});

// 4. Use database indexes
// Add to migration:
$table->index(['model_type', 'model_id']); // For polymorphic relations
$table->index('tenant_id'); // For tenant-based permissions

// 5. Optimize wildcard permissions
$user->givePermissionTo('posts.*'); // Better than multiple specific permissions
```

### Laravel Octane Support

[](#laravel-octane-support)

Shield is fully compatible with Laravel Octane:

```
// config/shield.php
'register_octane_reset_listener' => true,

// Automatically resets permission cache between requests
// Handles tenant context isolation
// Prevents memory leaks in long-running processes
```

⚙️ Artisan Commands
-------------------

[](#️-artisan-commands)

```
composer test
```

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

🆘 Support
---------

[](#-support)

- **Documentation**: [Full documentation](https://shield.litepie.com)
- **Issues**: [GitHub Issues](https://github.com/litepie/shield/issues)
- **Discussions**: [GitHub Discussions](https://github.com/litepie/shield/discussions)
- **Security**: Please email  for security vulnerabilities

🎯 Roadmap
---------

[](#-roadmap)

- **Vue.js Components**: Pre-built permission components
- **React Components**: Permission management components
- **GraphQL Support**: GraphQL permission checking
- **Audit Trails**: Built-in permission change logging
- **Permission Import/Export**: Bulk permission management
- **Advanced Caching**: Multi-layer caching strategies
- **Performance Dashboard**: Permission usage analytics

---

**Made with ❤️ by [Litepie](https://litepie.com)**

*Shield - Your Laravel application's guardian angel for role and permission management.*

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance59

Moderate activity, may be stable

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

2

Last Release

264d ago

PHP version history (2 changes)v1.0.0PHP ^8.1

v1.0.1PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1788735?v=4)[Renfos Technologies](/maintainers/Renfos)[@Renfos](https://github.com/Renfos)

---

Top Contributors

[![georgemjohn](https://avatars.githubusercontent.com/u/7950080?v=4)](https://github.com/georgemjohn "georgemjohn (2 commits)")

---

Tags

laravelsecurityauthorizationaclpermissionguardaccess-controlrolePolicy

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/litepie-shield/health.svg)

```
[![Health](https://phpackages.com/badges/litepie-shield/health.svg)](https://phpackages.com/packages/litepie-shield)
```

###  Alternatives

[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.9k89.8M1.0k](/packages/spatie-laravel-permission)[casbin/laravel-authz

An authorization library that supports access control models like ACL, RBAC, ABAC in Laravel.

324339.9k4](/packages/casbin-laravel-authz)[bezhansalleh/filament-shield

Filament support for `spatie/laravel-permission`.

2.8k2.9M88](/packages/bezhansalleh-filament-shield)[wnikk/laravel-access-rules

Simple system of ACR (access control rules) for Laravel, with roles, groups, unlimited inheritance and possibility of multiplayer use.

103.6k1](/packages/wnikk-laravel-access-rules)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)[efficiently/authority-controller

AuthorityController is an PHP authorization library for Laravel 5 which restricts what resources a given user is allowed to access.

15533.2k](/packages/efficiently-authority-controller)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
