# Filament Shield Filament Shield is a comprehensive access management package for Filament PHP admin panels that integrates with Spatie's Laravel Permission package. It provides an intuitive way to manage roles and permissions for Filament Resources, Pages, and Widgets with automatic policy generation, multi-tenancy support, and a built-in Role management UI. The package automatically discovers entities (resources, pages, widgets) across your Filament panels and generates corresponding permissions and policies. It supports super admin roles with gate interception, baseline panel user roles, custom ad-hoc permissions, and localized permission labels in 32+ languages. Shield provides fine-grained CLI tools for generating permissions, policies, and seeders while maintaining flexibility through extensive configuration options. ## Installation Install the package and set up Shield with automatic migrations and configuration. ```bash # Install the package via Composer composer require bezhansalleh/filament-shield # Publish the configuration file php artisan vendor:publish --tag="filament-shield-config" # Run the interactive setup command php artisan shield:setup # Or run setup with fresh migrations php artisan shield:setup --fresh ``` ## Add HasRoles Trait to User Model The User model must use Spatie's HasRoles trait for Shield to function properly. ```php default() ->id('admin') ->path('admin') ->plugins([ FilamentShieldPlugin::make() ->gridColumns([ 'default' => 1, 'sm' => 2, 'lg' => 3 ]) ->sectionColumnSpan(1) ->checkboxListColumns([ 'default' => 1, 'sm' => 2, 'lg' => 4, ]) ->resourceCheckboxListColumns([ 'default' => 1, 'sm' => 2, ]), ]); } } ``` ## Generate Permissions and Policies Use the shield:generate command to create permissions and policies for your Filament entities. ```bash # Generate permissions and policies for all entities in a panel php artisan shield:generate --all --panel=admin # Generate only policies (no permissions) php artisan shield:generate --all --option=policies --panel=admin # Generate only permissions (no policies) php artisan shield:generate --all --option=permissions --panel=admin # Generate for specific resources php artisan shield:generate --resource=UserResource,PostResource --panel=admin # Generate for specific pages php artisan shield:generate --page=Dashboard,Settings --panel=admin # Generate for specific widgets php artisan shield:generate --widget=StatsOverview,SalesChart --panel=admin # Exclude specific entities during generation php artisan shield:generate --all --resource=UserResource --exclude --panel=admin # Regenerate policies even if they exist php artisan shield:generate --all --ignore-existing-policies --panel=admin # Generate with tenancy relationships php artisan shield:generate --all --relationships --panel=admin ``` ## Create Super Admin User Create a super admin user with unrestricted access to the entire application. ```bash # Interactive super admin creation php artisan shield:super-admin --panel=admin # Create super admin for specific user php artisan shield:super-admin --user=1 --panel=admin # Create super admin with specific tenant php artisan shield:super-admin --user=1 --panel=admin --tenant=1 ``` ## HasPageShield Trait for Page Authorization Apply the HasPageShield trait to custom pages to enforce permission-based access control. ```php prepend($navigationGroup) ->trim() ->toString(); } } // Use the default builder with modified subject return FilamentShield::defaultPermissionKeyBuilder( affix: $affix, separator: $separator, subject: $subject, case: $case ); } ); } } ``` ## Assign Roles to Users in Resource Forms Use Filament form components to assign roles to users within your User resource. ```php schema([ Forms\Components\TextInput::make('name') ->required(), Forms\Components\TextInput::make('email') ->email() ->required(), // Using Select component for role assignment Forms\Components\Select::make('roles') ->relationship('roles', 'name') ->multiple() ->preload() ->searchable(), // Or using CheckboxList component Forms\Components\CheckboxList::make('roles') ->relationship('roles', 'name') ->searchable() ->columns(2), ]); } } ``` ## Assign Roles with Multi-Tenancy Support When using multi-tenancy, sync roles with the tenant's team foreign key. ```php schema([ Forms\Components\TextInput::make('name') ->required(), Forms\Components\TextInput::make('email') ->email() ->required(), // Role assignment with tenancy support Forms\Components\Select::make('roles') ->relationship('roles', 'name') ->saveRelationshipsUsing(function (Model $record, $state) { $record->roles()->syncWithPivotValues( $state, [config('permission.column_names.team_foreign_key') => getPermissionsTeamId()] ); }) ->multiple() ->preload() ->searchable(), ]); } } ``` ## Prohibit Destructive Commands in Production Prevent potentially destructive Shield commands from running in production environments. ```php app->isProduction()); // Or prohibit commands individually Commands\GenerateCommand::prohibit($this->app->isProduction()); Commands\InstallCommand::prohibit($this->app->isProduction()); Commands\PublishCommand::prohibit($this->app->isProduction()); Commands\SetupCommand::prohibit($this->app->isProduction()); Commands\SeederCommand::prohibit($this->app->isProduction()); Commands\SuperAdminCommand::prohibit($this->app->isProduction()); } } ``` ## Plugin Navigation Customization Customize the Shield Role resource navigation appearance in your panel. ```php navigationLabel('Access Control') ->navigationIcon('heroicon-o-shield-check') ->activeNavigationIcon('heroicon-s-shield-check') ->navigationGroup('Settings') ->navigationSort(10) ->navigationBadge('5') ->navigationBadgeColor('success') ->registerNavigation(true); ``` ## Plugin Labels and Search Customization Customize model labels and global search behavior for the Role resource. ```php modelLabel('Role') ->pluralModelLabel('Roles') ->recordTitleAttribute('name') ->titleCaseModelLabel(true) ->globallySearchable(true) ->globalSearchResultsLimit(50) ->forceGlobalSearchCaseInsensitive(true) ->splitGlobalSearchTerms(false); ``` ## Plugin Tenancy Configuration Configure Shield for multi-tenant applications with tenant-scoped roles. ```php scopeToTenant(true) ->tenantRelationshipName('organization') ->tenantOwnershipRelationshipName('owner'); ``` ## Localized Permission Labels Enable localized permission labels and generate translation files for different locales. ```php localizePermissionLabels(); ``` ```bash # Generate translation file for a specific locale php artisan shield:translation en --panel=admin php artisan shield:translation es --panel=admin php artisan shield:translation fr --panel=admin ``` ```php 'Create', 'delete' => 'Delete', 'delete_any' => 'Delete Any', 'force_delete' => 'Force Delete', 'force_delete_any' => 'Force Delete Any', 'replicate' => 'Replicate', 'reorder' => 'Reorder', 'restore' => 'Restore', 'restore_any' => 'Restore Any', 'update' => 'Update', 'view' => 'View', 'view_any' => 'View Any', // Pages 'view_dashboard' => 'Dashboard', // Widgets 'view_stats_overview' => 'Stats Overview', // Custom permissions 'approve_posts' => 'Approve Posts', ]; ``` ## Generate Permission Seeder Generate a seeder file to export and restore roles and permissions. ```bash # Generate seeder with permissions via roles php artisan shield:seeder --generate --option=permissions_via_roles # Generate seeder with direct permissions php artisan shield:seeder --generate --option=direct_permissions # Generate seeder with user data php artisan shield:seeder --generate --with-users # Force overwrite existing seeder php artisan shield:seeder --generate --force ``` ## Configuration Reference Configure Shield behavior through the config/filament-shield.php file. ```php [ 'slug' => 'shield/roles', 'show_model_path' => true, 'cluster' => null, 'tabs' => [ 'pages' => true, 'widgets' => true, 'resources' => true, 'custom_permissions' => false, // Enable to show custom permissions tab ], ], // Multi-tenancy configuration 'tenant_model' => null, // e.g., 'App\\Models\\Team' // User model for role assignments 'auth_provider_model' => 'App\\Models\\User', // Super admin configuration 'super_admin' => [ 'enabled' => true, 'name' => 'super_admin', 'define_via_gate' => false, 'intercept_gate' => 'before', ], // Panel user configuration 'panel_user' => [ 'enabled' => true, 'name' => 'panel_user', ], // Permission key generation 'permissions' => [ 'separator' => ':', // Separator between affix and subject 'case' => 'pascal', // pascal, camel, snake, kebab, upper_snake 'generate' => true, ], // Policy generation settings 'policies' => [ 'path' => app_path('Policies'), 'merge' => true, // Merge global methods with resource-specific 'generate' => true, 'methods' => [ 'viewAny', 'view', 'create', 'update', 'delete', 'deleteAny', 'restore', 'forceDelete', 'forceDeleteAny', 'restoreAny', 'replicate', 'reorder', ], 'single_parameter_methods' => [ 'viewAny', 'create', 'deleteAny', 'forceDeleteAny', 'restoreAny', 'reorder', ], ], // Localization settings 'localization' => [ 'enabled' => false, 'key' => 'shield-permissions', ], // Resource permission settings 'resources' => [ 'subject' => 'model', // 'model' or 'class' 'manage' => [ // Override methods for specific resources // App\Filament\Resources\PostResource::class => ['viewAny', 'view', 'create'], ], 'exclude' => [ // Resources to exclude from permission generation ], ], // Page permission settings 'pages' => [ 'subject' => 'class', 'prefix' => 'view', 'exclude' => [ \Filament\Pages\Dashboard::class, ], ], // Widget permission settings 'widgets' => [ 'subject' => 'class', 'prefix' => 'view', 'exclude' => [ \Filament\Widgets\AccountWidget::class, \Filament\Widgets\FilamentInfoWidget::class, ], ], // Custom ad-hoc permissions 'custom_permissions' => [ // 'Impersonate:User' => 'Impersonate User', // 'Export:Order' => 'Export Orders', ], // Entity discovery across panels 'discovery' => [ 'discover_all_resources' => false, 'discover_all_widgets' => false, 'discover_all_pages' => false, ], // Role policy auto-registration 'register_role_policy' => true, ]; ``` ## Policy Enforcement with Gate Register policies manually for models outside the default namespace or from third-party packages. ```php