Dans le [Module 4], nous avons doté notre application EquipFlow d’une logique métier solide : scopes d’isolation du matériel disponible, actions rapides avec modales interactives et gestionnaires de relations.
Cependant, livrer une application d’entreprise sans cloisonnement strict des accès revient à laisser la porte grande ouverte. Dans une PME ou une ESN, un gestionnaire d’atelier ne doit pas avoir le droit de modifier les tarifs de location, et un commercial ne devrait pas pouvoir supprimer définitivement un client ou purger l’historique des affectations.
Dans ce module, nous allons verrouiller notre panneau Filament 5 en implémentant :
- Un contrôle d’accès basé sur les rôles (RBAC) à l’aide d’Enums PHP 8.6 et de
spatie/laravel-permission. - Les Policies Laravel 13 nativement reconnues par Filament pour interdire l’accès aux pages ou aux actions critiques.
- Le masquage granulaire de colonnes et de champs de formulaires selon les permissions de l’utilisateur connecté.
- L’authentification multifacteur (2FA TOTP) native pour sécuriser les comptes administrateurs.
Modélisation des Rôles & Permissions
Pour garantir la maintenabilité du système, nous couplons le paquet de référence spatie/laravel-permission avec un Enum PHP typé.
Étape A : Installation du composant
composer require spatie/laravel-permission:^6.0
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate
Étape B : Définition des Rôles avec un Enum typé
Créez le fichier app/Enums/UserRole.php :
declare(strict_types=1);
namespace App\Enums;
enum UserRole: string
{
case Admin = 'admin';
case Manager = 'manager';
case Technician = 'technician';
public function label(): string
{
return match ($this) {
self::Admin => 'Administrateur',
self::Manager => 'Responsable Commercial',
self::Technician => 'Technicien Parc',
};
}
}
Étape C : Mise à jour du modèle User
Ajoutez le trait HasRoles dans app/Models/User.php :
declare(strict_types=1);
namespace App\Models;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable implements FilamentUser
{
use HasFactory, Notifiable, HasRoles;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
/**
* Contrôle qui a le droit d'accéder au panneau Filament
*/
public function canAccessPanel(Panel $panel): bool
{
// Seuls les utilisateurs possédant un rôle défini peuvent se connecter
return $this->hasAnyRole([
UserRole::Admin->value,
UserRole::Manager->value,
UserRole::Technician->value,
]);
}
}
Verrouillage des Ressources via les Policies Laravel 13
Filament 5 respecte scrupuleusement la convention des Policies de Laravel. Dès qu’une Policy portant le même nom qu’un modèle existe, Filament adapte automatiquement l’interface : les boutons de suppression disparaissent, les formulaires passent en lecture seule et les menus non autorisés sont masqués de la barre latérale.
Générons la Policy pour le modèle Client :
php artisan make:policy ClientPolicy --model=ClientDans app/Policies/ClientPolicy.php, implémentons les autorisations selon nos rôles :
declare(strict_types=1);
namespace App\Policies;
use App\Enums\UserRole;
use App\Models\Client;
use App\Models\User;
class ClientPolicy
{
/**
* Autorise la vue du listing des clients
*/
public function viewAny(User $user): bool
{
return $user->hasAnyRole([
UserRole::Admin->value,
UserRole::Manager->value,
UserRole::Technician->value,
]);
}
/**
* Autorise la consultation d'une fiche client spécifique
*/
public function view(User $user, Client $client): bool
{
return $this->viewAny($user);
}
/**
* Seuls les Admins et les Managers peuvent créer un client
*/
public function create(User $user): bool
{
return $user->hasAnyRole([
UserRole::Admin->value,
UserRole::Manager->value,
]);
}
/**
* Seuls les Admins et les Managers peuvent éditer un client
*/
public function update(User $user, Client $client): bool
{
return $user->hasAnyRole([
UserRole::Admin->value,
UserRole::Manager->value,
]);
}
/**
* Seul l'Administrateur peut supprimer un client
*/
public function delete(User $user, Client $client): bool
{
return $user->hasRole(UserRole::Admin->value);
}
}
Dès cet instant, un utilisateur avec le profil technician verra la liste des clients, mais les boutons « Nouveau client », « Éditer » et « Supprimer » seront automatiquement absents de son interface, sans une seule condition Blade manuelle.
Masquage granulaire de données sensibles (Colonnes & Champs)
Certaines données financières, comme le coût mensuel d’un équipement ou la marge sur un contrat, ne doivent pas être visibles par les techniciens d’atelier.
Filament permet de conditionner la visibilité de n’importe quel composant de formulaire ou de table via la méthode visible().
Dans la table des affectations (AssignmentResource.php)
Masquons la colonne du coût de location pour qu’elle ne soit visible que par la direction :
Tables\Columns\TextColumn::make('monthly_cost')
->label('Loyer Mensuel')
->money('EUR')
->sortable()
->visible(fn (): bool => auth()->user()?->hasAnyRole([
UserRole::Admin->value,
UserRole::Manager->value
]) ?? false),
Dans le formulaire d’affectation
Empêchons également la modification de ce coût aux techniciens :
Forms\Components\TextInput::make('monthly_cost')
->label('Coût mensuel HT')
->numeric()
->prefix('€')
->required()
->disabled(fn (): bool => !auth()->user()?->hasAnyRole([
UserRole::Admin->value,
UserRole::Manager->value
])),
Activation de l’authentification multifacteur (2FA TOTP)
Filament 5 propose une prise en charge native de l’authentification à deux facteurs compatible avec des applications comme Google Authenticator, Bitwarden ou 1Password.
Ouvrez app/Providers/Filament/AdminPanelProvider.php et ajoutez la configuration 2FA sur le panel :
use Filament\Pages\Auth\EditProfile;
public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('admin')
->login()
// Activation du profil utilisateur avec 2FA
->profile(EditProfile::class)
->authGuard('web')
// Active le protocole d'authentification à deux facteurs
->requiresTwoFactorAuthentication()
// ... reste de la configuration du panel
}
En activant requiresTwoFactorAuthentication(), Filament oblige les utilisateurs à configurer une application TOTP dès leur première connexion, avec génération de codes de récupération d’urgence chiffrés.
Mise à jour du Seeder pour tester les rôles
Dans database/seeders/DatabaseSeeder.php, configurons les comptes de démonstration pour chaque rôle :
namespace Database\Seeders;
use App\Enums\UserRole;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use Spatie\Permission\Models\Role;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
// Création des rôles
$adminRole = Role::firstOrCreate(['name' => UserRole::Admin->value]);
$managerRole = Role::firstOrCreate(['name' => UserRole::Manager->value]);
$techRole = Role::firstOrCreate(['name' => UserRole::Technician->value]);
// Compte Administrateur
$admin = User::firstOrCreate(
['email' => 'admin@equipflow.test'],
['name' => 'Directeur Technique', 'password' => Hash::make('password')]
);
$admin->syncRoles([$adminRole]);
// Compte Responsable Commercial
$manager = User::firstOrCreate(
['email' => 'commercial@equipflow.test'],
['name' => 'Responsable Grands Comptes', 'password' => Hash::make('password')]
);
$manager->syncRoles([$managerRole]);
// Compte Technicien
$tech = User::firstOrCreate(
['email' => 'atelier@equipflow.test'],
['name' => 'Technicien Support', 'password' => Hash::make('password')]
);
$tech->syncRoles([$techRole]);
// ... exécution des factories Client, Equipment et Assignment
}
}
Réinitialisez la base pour appliquer ces règles :
php artisan migrate:fresh --seed
Résumé du Module 5
Notre application dispose à présent d’une sécurité conforme aux exigences d’entreprise :
- Cloisonnement RBAC : chaque utilisateur n’accède qu’aux fonctions liées à son métier.
- Policies natives : protection imperméable au niveau serveur empêchant toute manipulation non autorisée d’URL ou d’API.
- Confidentialité des données : masquage dynamique des colonnes de prix et champs sensibles.
- 2FA obligatoire : protection des comptes d’administration contre le vol d’identifiants.
Dans le Module 6, nous nous concentrerons sur le pilotage métier : Tableaux de bord, KPIs et Exports de données (widgets de statistiques réactifs, graphiques d’activité et génération de bordereaux PDF volumineux).



