PHP code example of litepie / shield

1. Go to this page and download the library: Download litepie/shield library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

litepie / shield example snippets


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
];

use Litepie\Shield\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;

    // ...
}

use Litepie\Shield\Traits\HasPermissions;

class ApiClient extends Model
{
    use HasPermissions;
}

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);

// 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
]);

// 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']);

// 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']);

// 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']);

// 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

// 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
}

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);
    }
}

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

// 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');

// 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

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

// 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

// 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');

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]);
    }
}

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

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);
    }
}

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']);
});

// 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);
});

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);
    }
}

'tenants' => true,

// 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();

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

// 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

// 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.

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

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);
    }
}

/** @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'));
}

/** @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);
}

/** @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);
}

// 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);
            }
        }
    }
}

// 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();

// 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();

// 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,
        ];
    });

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

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

// 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,
    ],
];

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(),
            ],
        ]);
    }
}

// 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}");
    }
}

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

// 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']);
});

// 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');

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']);
    }
}

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

// 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

// 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

// 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
bash
php artisan vendor:publish --provider="Litepie\Shield\ShieldServiceProvider"
bash
php artisan migrate
bash
php artisan shield:create-superuser
bash
php artisan shield:create-superuser --name="Administrator" --email="[email protected]" --password="secure-password"