Using SystemRoles in Your App
Blade, Gates and Policies
SystemRoles works alongside Laravel's own authorization. Connecting the two lets you use @can, $user->can(), Gate::allows() and ->can() on routes with SystemRoles permissions.
Connect SystemRoles to Laravel's Gate#
In App\Providers\AppServiceProvider::boot() (or AuthServiceProvider on Laravel 9/10):
use BabeRuka\SystemRoles\Models\SystemRolesIn;
use BabeRuka\SystemRoles\Services\SystemRolesService;
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
// The super admin passes every ability.
Gate::before(function ($user) {
return SystemRolesService::isSuperAdmin($user) ? true : null;
});
// Any ability that is a SystemRoles permission is checked against the matrix.
Gate::after(function ($user, string $ability, ?bool $result) {
if ($result !== null) {
return $result; // a policy or gate already decided
}
$roleId = SystemRolesService::roleIdForUser($user->getKey());
return SystemRolesService::roleHas($roleId, $ability);
});
}Now every SystemRoles permission is a Laravel ability:
$user->can('invoice.approve');
Gate::authorize('invoice.approve');
Route::post('/invoices/{invoice}/approve', ...)->can('invoice.approve');In Blade#
@can('invoice.approve')
<button class="btn btn-success">Approve</button>
@endcan
@cannot('invoice.delete')
<span class="text-muted">Read only</span>
@endcannotA custom directive for roles:
use Illuminate\Support\Facades\Blade;
use BabeRuka\SystemRoles\Models\SystemRoles;
use BabeRuka\SystemRoles\Services\SystemRolesService;
Blade::if('role', function (string ...$guards) {
$roleId = SystemRolesService::roleIdForUser(auth()->id());
$guard = SystemRoles::whereKey($roleId)->value('role_guard_name');
return SystemRolesService::isSuperAdminRole($roleId) || in_array($guard, $guards, true);
});
Blade::if('superadmin', fn () => SystemRolesService::isSuperAdmin());@role('admin', 'manager')
<a href="{{ route('reports.index') }}">Reports</a>
@endrole
@superadmin
<a href="{{ route('systemroles.admin.roles.index') }}">Roles & permissions</a>
@endsuperadminHiding a link is for convenience only. Always protect the route itself too.
In policies#
Policies answer questions about a specific record ("may this user edit this invoice?"). Combine a permission with ownership:
class InvoicePolicy
{
public function update(User $user, Invoice $invoice): bool
{
$roleId = SystemRolesService::roleIdForUser($user->id);
if (SystemRolesService::roleHas($roleId, 'invoice.update.any')) {
return true;
}
return SystemRolesService::roleHas($roleId, 'invoice.update.own')
&& $invoice->owner_id === $user->id;
}
}The Gate::before hook above lets the super admin pass every policy too.
In API resources and JSON#
Send the user's permissions to a front end (Vue, React, mobile) once after login:
return [
'user' => $user->only('id', 'name', 'email'),
'role_id' => $roleId = SystemRolesService::roleIdForUser($user->id),
'super_admin' => SystemRolesService::isSuperAdminRole($roleId),
'permissions' => collect(SystemRolesService::permissionsForRole($roleId))->filter()->keys(),
];The front end uses this list to show or hide things. The API still checks every request on the server.