To achieve a global policy or gate for every resource in a Laravel application, you can use a combination of route model binding, middleware, and a single gate or policy method that checks the team ownership of the bound model. Here's a step-by-step solution:
-
Define a Gate or Policy Method: First, define a gate or policy method that checks if the authenticated user is a member of the team that owns the resource.
// In AuthServiceProvider or any service provider you prefer use Illuminate\Support\Facades\Gate; public function boot() { // ... Gate::define('view-team-resource', function ($user, $resource) { return $user->team_id === $resource->team_id; }); } -
Create a Middleware: Create a middleware that will extract the resource from the route and check the gate for the given resource.
// Run `php artisan make:middleware CheckTeamOwnership` namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Gate; class CheckTeamOwnership { public function handle($request, Closure $next) { $routeParameters = $request->route()->parameters(); foreach ($routeParameters as $parameter) { if (is_object($parameter) && method_exists($parameter, 'team')) { if (Gate::denies('view-team-resource', $parameter)) { abort(403); } break; } } return $next($request); } }In this middleware, we assume that your resources have a
team()relationship method or ateam_idproperty that can be used to check ownership. -
Register the Middleware: Register the middleware in your
app/Http/Kernel.phpfile.protected $routeMiddleware = [ // ... 'team.ownership' => \App\Http\Middleware\CheckTeamOwnership::class, ]; -
Apply Middleware to Routes: Apply the middleware to your resource routes. You can do this in your
routes/web.phporroutes/api.phpfile.Route::middleware(['auth', 'team.ownership'])->group(function () { // Define your resource routes here Route::resource('projects', 'ProjectController'); // ... other resources });Ensure that your controllers use route model binding so that the middleware can automatically inject the model instance into the route.
-
Route Model Binding: If you haven't already, make sure to use route model binding in your controller methods. Laravel will automatically resolve the model instances for you.
public function show(Project $project) { // $project is automatically resolved and injected by Laravel return view('projects.show', compact('project')); }
With this setup, you have a single gate that checks team ownership, and a middleware that applies this check to all routes within the group. This approach avoids the need to write repetitive logic for each resource and keeps your authorization logic centralized.