RBAC - v1.0.0
Middleware
The service provider aliases permission to ArtisanPackUI\Rbac\Http\Middleware\CheckPermission. Apply it to any route that requires one or more permissions.
Single permission
Route::get('/posts/{post}/publish', PublishController::class)
->middleware('permission:posts.publish');
Multiple permissions (OR)
Comma-separate permissions to require any of them:
Route::get('/admin', AdminController::class)
->middleware('permission:admin.dashboard,admin.metrics');
The user only needs one of admin.dashboard or admin.metrics to proceed.
Behaviour
| State | HTTP response |
|---|---|
| Unauthenticated (guest) | 401 Unauthorized |
| Authenticated, has one of the listed permissions | passes to controller (200 or whatever the controller returns) |
| Authenticated, has none of the listed permissions | 403 Forbidden |
Both abort codes use Laravel's default abort() helper, so your application's normal 401 / 403 error views render as expected.
Implementation reference
class CheckPermission
{
public function handle(Request $request, Closure $next, string ...$permissions)
{
if (Auth::guest()) {
abort(401);
}
$user = Auth::user();
foreach ($permissions as $permission) {
if ($user->can($permission)) {
return $next($request);
}
}
abort(403);
}
}
The middleware delegates to $user->can(), which routes through the Gate integration and ultimately calls HasPermissions::hasPermissionTo(). So permissions inherited via the role hierarchy are honoured here.
When to use this vs other patterns
- Use the middleware for route-level gating where a missing permission should produce an HTTP 403.
- Use
@permissionBlade directives for view-level gating where a missing permission should hide UI elements. - Use
$user->can()/Gate::allows()in controllers when the response depends on the permission outcome (e.g. show different fields, branch behaviour). - Use Policies when authorization logic involves the resource (e.g. "user can edit this post only if they authored it"). The Gate integration composes cleanly with policies — RBAC handles broad capabilities, policies handle per-resource rules.
"AND" semantics
The middleware is OR-by-design. If you need AND semantics (user must hold every listed permission), apply the middleware multiple times:
Route::middleware(['permission:admin.dashboard', 'permission:admin.metrics']);
Or implement a custom middleware that calls $user->hasPermissionTo() for each requirement.