From 13f36e8ec0950d75cc3552f4b9e5d1a4680447f0 Mon Sep 17 00:00:00 2001 From: javier Date: Wed, 17 Jun 2026 19:15:58 +0200 Subject: [PATCH] feat(authz): per-route permission gating for /admin (granular admin roles) Finishes Phase 2: the /admin route group no longer requires 'manage all' globally. Each route is gated by its specific permission so a non-super-admin role can be granted partial admin access: - /admin/users (+show) -> can:view users; create -> can:create users; edit -> can:edit users - /admin/roles, roles/*, permissions -> can:manage roles - Aligned the role screens' mount checks (RoleForm/RoleView/RolePermissionManager) from 'manage all' to 'manage roles'. - Nav 'Administrator' link now shows on can('view users'). Admins keep full access via Gate::before (manage all). Closure routes (users/roles lists) are now protected at the route level. Co-Authored-By: Claude Opus 4.8 (1M context) --- app/Livewire/RoleForm.php | 2 +- app/Livewire/RolePermissionManager.php | 2 +- app/Livewire/RoleView.php | 2 +- .../livewire/layout/navigation.blade.php | 2 +- routes/web.php | 22 +++++++++---------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/Livewire/RoleForm.php b/app/Livewire/RoleForm.php index 3864741..3a48dc3 100644 --- a/app/Livewire/RoleForm.php +++ b/app/Livewire/RoleForm.php @@ -21,7 +21,7 @@ class RoleForm extends Component public function mount(?Role $role = null): void { - abort_unless(Auth::user()?->can(self::CORE_PERMISSION), 403); + abort_unless(Auth::user()?->can('manage roles'), 403); if ($role && $role->exists) { $this->role = $role; diff --git a/app/Livewire/RolePermissionManager.php b/app/Livewire/RolePermissionManager.php index 0671ce5..532649a 100644 --- a/app/Livewire/RolePermissionManager.php +++ b/app/Livewire/RolePermissionManager.php @@ -21,7 +21,7 @@ class RolePermissionManager extends Component public function mount(): void { - abort_unless(Auth::user()?->can(self::CORE_PERMISSION), 403); + abort_unless(Auth::user()?->can('manage roles'), 403); } private function flushCache(): void diff --git a/app/Livewire/RoleView.php b/app/Livewire/RoleView.php index fb437fe..c33cede 100644 --- a/app/Livewire/RoleView.php +++ b/app/Livewire/RoleView.php @@ -23,7 +23,7 @@ class RoleView extends Component public function mount(Role $role): void { - abort_unless(Auth::user()?->can(self::CORE_PERMISSION), 403); + abort_unless(Auth::user()?->can('manage roles'), 403); $this->role = $role; } diff --git a/resources/views/livewire/layout/navigation.blade.php b/resources/views/livewire/layout/navigation.blade.php index 57f72d0..a96fa9e 100644 --- a/resources/views/livewire/layout/navigation.blade.php +++ b/resources/views/livewire/layout/navigation.blade.php @@ -49,7 +49,7 @@ new class extends Component - @can('manage all') + @can('view users')