<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserHasRole
{
public function handle(Request $request, Closure $next, string ...$roles): Response
{
if (!$request->user()) {
abort(401, 'Unauthenticated');
}
if (!$request->user()->hasAnyRole($roles)) {
abort(403, 'Insufficient permissions');
}
return $next($request);
}
}
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
class LogApiRequests
{
public function handle(Request $request, Closure $next): Response
{
$startTime = microtime(true);
// Modify request if needed
$request->headers->set('X-Request-ID', $requestId = str()->uuid());
$response = $next($request);
// Log after response is generated
$duration = round((microtime(true) - $startTime) * 1000, 2);
Log::info('API Request', [
'request_id' => $requestId,
'method' => $request->method(),
'path' => $request->path(),
'status' => $response->getStatusCode(),
'duration_ms' => $duration,
'user_id' => $request->user()?->id,
]);
return $response;
}
public function terminate(Request $request, Response $response): void
{
// Runs after response sent to browser
// Good for heavy operations like analytics
}
}
<?php
use Illuminate\Support\Facades\Route;
Route::middleware(['auth:sanctum', 'role:admin,editor'])
->group(function () {
Route::get('/posts', [PostController::class, 'index']);
Route::post('/posts', [PostController::class, 'store']);
});
Route::middleware(['auth:sanctum', 'role:admin'])
->prefix('admin')
->group(function () {
Route::get('/users', [UserController::class, 'index']);
Route::delete('/users/{user}', [UserController::class, 'destroy']);
});
Middleware intercepts HTTP requests before they reach controllers, perfect for authentication, logging, or request modification. I create middleware classes with a handle() method that receives the request and a $next closure. Middleware can inspect/modify requests before passing them forward or inspect/modify responses after. Global middleware runs on every request, while route middleware applies selectively. Middleware groups like web and api apply common middleware stacks. The terminate() method runs after the response is sent to the browser, useful for logging or cleanup. Middleware parameters enable reusable logic—a role middleware that accepts role names. The middleware pipeline is Laravel's request/response filter chain.