# Laravel Middleware a fondo: Autenticación, Rate Limiting y Middleware personalizado > Guía completa sobre middleware en Laravel con ejemplos prácticos: guards de autenticación, limitación de tasa con throttle, creación de middleware personalizado y patrones avanzados para aplicaciones en producción. - Published: 2026-04-16 - Updated: 2026-04-16 - Author: SharpSkill - Tags: laravel, middleware, authentication, rate-limiting, php - Reading time: 10 min --- El middleware de Laravel actúa como una capa de filtrado entre las solicitudes HTTP entrantes y la lógica de la aplicación. Cada solicitud atraviesa un pipeline de clases middleware antes de llegar a un controlador, y cada respuesta recorre el mismo pipeline en sentido inverso. Comprender este mecanismo resulta esencial para construir aplicaciones Laravel seguras y de alto rendimiento en 2026. > **Middleware en pocas palabras** > > El middleware intercepta las solicitudes HTTP antes de que lleguen a las rutas. Laravel 12 registra todos los middleware en `bootstrap/app.php` mediante una API fluida. Los middleware integrados gestionan la autenticación, la protección CSRF, el manejo de sesiones y la limitación de tasa de forma nativa. ## Cómo funciona el pipeline de middleware en Laravel El kernel HTTP de Laravel procesa cada solicitud a través de una pila de middleware. Cada middleware recibe la solicitud, ejecuta su lógica y, o bien la pasa a la siguiente capa mediante `$next($request)`, o bien cortocircuita el pipeline devolviendo una respuesta directamente. Esta arquitectura sigue el patrón de diseño Chain of Responsibility. Un middleware puede actuar **antes** de que la solicitud llegue al controlador (por ejemplo, verificaciones de autenticación), **después** de que se genere la respuesta (por ejemplo, agregando encabezados), o en ambos momentos. ```php // app/Http/Middleware/LogRequestTime.php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Symfony\Component\HttpFoundation\Response; class LogRequestTime { public function handle(Request $request, Closure $next): Response { $start = microtime(true); // Capture start time $response = $next($request); // Pass to next middleware $duration = microtime(true) - $start; Log::info('Request completed', [ 'url' => $request->url(), 'method' => $request->method(), 'duration' => round($duration * 1000, 2) . 'ms', ]); return $response; // Return response up the stack } } ``` Este middleware envuelve la solicitud: registra el tiempo de inicio **antes** del procesamiento y registra la duración **después** de que la respuesta regresa. Este patrón antes/después es el núcleo del funcionamiento del middleware. ## Middleware de autenticación: protegiendo las rutas Laravel incluye el alias de middleware `auth`, mapeado a `Illuminate\Auth\Middleware\Authenticate`. Al aplicarlo a una ruta, se garantiza que solo los usuarios autenticados puedan acceder a ella. Los usuarios no autenticados reciben una respuesta 401 (API) o son redirigidos a la página de inicio de sesión (web). ```php // routes/web.php use App\Http\Controllers\DashboardController; use App\Http\Controllers\ProfileController; // Single route protection Route::get('/dashboard', [DashboardController::class, 'index']) ->middleware('auth'); // Group protection for multiple routes Route::middleware('auth')->group(function () { Route::get('/profile', [ProfileController::class, 'show']); Route::put('/profile', [ProfileController::class, 'update']); Route::delete('/profile', [ProfileController::class, 'destroy']); }); ``` ### Autenticación con múltiples guards Las aplicaciones con varios tipos de usuarios (panel de administración, área de clientes, API) se benefician de la [autenticación basada en guards](/technologies/laravel/interview-questions/authentication). El middleware `auth` acepta un parámetro de guard para especificar qué driver de autenticación utilizar. ```php // routes/api.php // API routes use the 'sanctum' guard Route::middleware('auth:sanctum')->group(function () { Route::get('/user', fn (Request $request) => $request->user()); Route::apiResource('/orders', OrderController::class); }); // routes/web.php // Admin routes use a custom 'admin' guard Route::middleware('auth:admin')->prefix('admin')->group(function () { Route::get('/dashboard', [AdminController::class, 'index']); Route::get('/users', [AdminController::class, 'users']); }); ``` El parámetro de guard después de los dos puntos indica a Laravel qué configuración de autenticación verificar. Este enfoque mantiene la lógica de autenticación limpia y separada entre las distintas partes de la aplicación. > **Middleware Guest** > > El middleware `guest` es el inverso de `auth`: solo permite el paso a usuarios no autenticados. Al aplicarlo a las rutas de inicio de sesión y registro, se evita que los usuarios ya autenticados accedan a esas páginas. ## Limitación de tasa con el middleware Throttle La limitación de tasa mediante middleware en Laravel protege las rutas contra abusos usando el middleware integrado `throttle`. Su forma más simple acepta dos parámetros: el número máximo de solicitudes y la ventana de tiempo en minutos. ```php // routes/api.php // Allow 60 requests per minute per user Route::middleware('throttle:60,1')->group(function () { Route::get('/posts', [PostController::class, 'index']); Route::get('/posts/{post}', [PostController::class, 'show']); }); // Stricter limit for write operations Route::middleware(['auth:sanctum', 'throttle:10,1'])->group(function () { Route::post('/posts', [PostController::class, 'store']); Route::put('/posts/{post}', [PostController::class, 'update']); }); ``` ### Rate limiters con nombre para control avanzado Definir rate limiters con nombre en `AppServiceProvider` ofrece un control granular sobre los límites basados en el contexto del usuario. Este enfoque resulta más flexible que los parámetros throttle en línea. ```php // app/Providers/AppServiceProvider.php use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Support\Facades\RateLimiter; use Illuminate\Http\Request; public function boot(): void { // API rate limiter with tiered access RateLimiter::for('api', function (Request $request) { $user = $request->user(); if ($user?->hasSubscription('enterprise')) { return Limit::perMinute(500)->by($user->id); // Enterprise: 500/min } if ($user) { return Limit::perMinute(100)->by($user->id); // Authenticated: 100/min } return Limit::perMinute(20)->by($request->ip()); // Anonymous: 20/min }); // Login limiter to prevent brute force RateLimiter::for('login', function (Request $request) { return Limit::perMinute(5) ->by($request->ip()) // Key by IP address ->response(function () { // Custom exceeded response return response()->json([ 'message' => 'Too many login attempts. Try again in a minute.', ], 429); }); }); } ``` La aplicación de limiters con nombre a las rutas utiliza la sintaxis `throttle:name`: ```php // routes/api.php Route::middleware('throttle:api')->group(function () { Route::apiResource('/posts', PostController::class); }); // routes/web.php Route::middleware('throttle:login') ->post('/login', [AuthController::class, 'login']); ``` El rate limiter escalonado del ejemplo anterior muestra un patrón de producción: los usuarios enterprise obtienen límites más altos, los usuarios autenticados reciben límites moderados, y las solicitudes anónimas se restringen de forma agresiva. El método `by()` determina la clave de limitación: el identificador de usuario para usuarios autenticados y la dirección IP como alternativa. ## Construir middleware personalizado desde cero La creación de [middleware](/technologies/laravel/interview-questions/middleware) personalizado cubre escenarios que los middleware integrados no manejan. El comando Artisan `make:middleware` genera una nueva clase con la estructura correcta. ```bash php artisan make:middleware EnsureUserHasRole ``` ### Middleware de control de acceso por roles Un patrón común de middleware personalizado aplica [autorización basada en roles](/technologies/laravel/interview-questions/authorization-policies) a nivel de ruta, aceptando nombres de roles como parámetros. ```php // app/Http/Middleware/EnsureUserHasRole.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 { $user = $request->user(); if (! $user || ! $user->hasAnyRole($roles)) { abort(403, 'Insufficient permissions.'); } return $next($request); } } ``` El parámetro variádico `...$roles` permite pasar múltiples roles separados por comas. El registro y la utilización se presentan así: ```php // bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'role' => \App\Http\Middleware\EnsureUserHasRole::class, ]); }) // routes/web.php Route::middleware('role:admin')->group(function () { Route::get('/admin', [AdminController::class, 'index']); }); // Multiple roles: admin OR editor can access Route::middleware('role:admin,editor')->group(function () { Route::resource('/articles', ArticleController::class); }); ``` ### Middleware de transformación de solicitudes Un middleware puede modificar la solicitud antes de que llegue al controlador. A continuación, un middleware para API JSON que impone encabezados de tipo de contenido y limpia las entradas de tipo string: ```php // app/Http/Middleware/ApiRequestSanitizer.php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class ApiRequestSanitizer { public function handle(Request $request, Closure $next): Response { // Reject non-JSON requests on API routes if (! $request->expectsJson() && $request->isMethod('POST')) { return response()->json( ['error' => 'Content-Type must be application/json'], 415 ); } // Trim all string inputs $input = $request->all(); array_walk_recursive($input, function (&$value) { if (is_string($value)) { $value = trim($value); } }); $request->merge($input); return $next($request); } } ``` Este middleware gestiona dos responsabilidades: valida el tipo de contenido para solicitudes POST y sanea todas las entradas de texto eliminando espacios en blanco innecesarios. ## Registro de middleware en Laravel 12 Laravel 12 centraliza el registro de todos los middleware en `bootstrap/app.php`. Esta metodología reemplazó el antiguo archivo `app/Http/Kernel.php` que existía antes de Laravel 11. ```php // bootstrap/app.php use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Middleware; return Application::configure(basePath: dirname(__DIR__)) ->withMiddleware(function (Middleware $middleware) { // Global middleware (runs on every request) $middleware->append( \App\Http\Middleware\LogRequestTime::class ); // Add to the 'web' middleware group $middleware->web(append: [ \App\Http\Middleware\TrackPageViews::class, ]); // Add to the 'api' middleware group $middleware->api(prepend: [ \App\Http\Middleware\ApiRequestSanitizer::class, ]); // Register aliases for route-level use $middleware->alias([ 'role' => \App\Http\Middleware\EnsureUserHasRole::class, 'subscribed' => \App\Http\Middleware\EnsureUserIsSubscribed::class, ]); // Control execution order $middleware->priority([ \Illuminate\Session\Middleware\StartSession::class, \Illuminate\Auth\Middleware\Authenticate::class, \App\Http\Middleware\EnsureUserHasRole::class, ]); }) ->create(); ``` El array `priority` cobra importancia cuando se asignan múltiples middleware a la misma ruta. Laravel los ordena según esta lista, garantizando que la sesión se inicie antes de ejecutar la autenticación, y que la autenticación se complete antes de las verificaciones de roles. > **Orden de ejecución del middleware** > > Los middleware se ejecutan en el orden de registro. Para los middleware de ruta, el array `priority` sobrescribe el orden predeterminado. Siempre se debe colocar la autenticación antes de la autorización para evitar verificar roles en solicitudes no autenticadas. ## Middleware terminable para tareas post-respuesta El middleware terminable ejecuta lógica **después** de que la respuesta ha sido enviada al cliente. Resulta especialmente útil para tareas de registro, analítica o limpieza que no deben bloquear al usuario. ```php // app/Http/Middleware/CollectAnalytics.php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Symfony\Component\HttpFoundation\Response; class CollectAnalytics { public function handle(Request $request, Closure $next): Response { return $next($request); // Pass through without delay } public function terminate(Request $request, Response $response): void { // Runs after response is sent to client DB::table('analytics')->insert([ 'path' => $request->path(), 'method' => $request->method(), 'status_code' => $response->getStatusCode(), 'user_id' => $request->user()?->id, 'ip' => $request->ip(), 'created_at' => now(), ]); } } ``` El método `terminate` recibe tanto la solicitud original como la respuesta final. Se recomienda registrar el middleware como singleton en `AppServiceProvider` para asegurar que la misma instancia maneje tanto `handle()` como `terminate()`. ## Patrones de middleware para producción Varios patrones de middleware aparecen de manera recurrente en las [aplicaciones Laravel](/blog/laravel/laravel-11-building-complete-application) en producción. **Bypass del modo mantenimiento**: permitir que las IPs internas accedan a la aplicación durante el mantenimiento: ```php // app/Http/Middleware/MaintenanceBypass.php class MaintenanceBypass { private array $allowedIps = ['192.168.1.0/24', '10.0.0.1']; public function handle(Request $request, Closure $next): Response { if (app()->isDownForMaintenance()) { foreach ($this->allowedIps as $ip) { if ($request->ip() === $ip) { return $next($request); } } } return $next($request); } } ``` **Encabezados de seguridad**: agregar HSTS, política de seguridad del contenido y otros encabezados a cada respuesta: ```php // app/Http/Middleware/SecurityHeaders.php class SecurityHeaders { public function handle(Request $request, Closure $next): Response { $response = $next($request); $response->headers->set('X-Content-Type-Options', 'nosniff'); $response->headers->set('X-Frame-Options', 'SAMEORIGIN'); $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin'); $response->headers->set( 'Strict-Transport-Security', 'max-age=31536000; includeSubDomains' ); return $response; } } ``` Estos patrones ilustran las dos posiciones principales del middleware: **antes** de la solicitud (el bypass de mantenimiento verifica la IP y potencialmente bloquea el acceso) y **después** de la respuesta (los encabezados de seguridad modifican la respuesta saliente). ## Conclusión - El middleware de Laravel opera como un pipeline: cada clase procesa la solicitud, actúa sobre ella y la pasa al siguiente nivel o cortocircuita con una respuesta - El middleware `auth` protege las rutas con autenticación basada en guards, soportando múltiples tipos de usuarios mediante la sintaxis `auth:guard` - La limitación de tasa a través del middleware `throttle` y las definiciones con nombre `RateLimiter::for()` habilitan un control de acceso escalonado según el contexto del usuario - Los middleware personalizados gestionan responsabilidades transversales como verificaciones de roles, saneamiento de solicitudes y encabezados de seguridad sin sobrecargar los controladores - Todo el registro de middleware en Laravel 12 ocurre en `bootstrap/app.php` mediante una API fluida, con `priority` para controlar el orden de ejecución - El middleware terminable ejecuta tareas post-respuesta (analítica, registro) sin impactar la latencia percibida por el usuario - Los parámetros de middleware mediante la sintaxis `:param` mantienen las definiciones de ruta expresivas y las clases middleware reutilizables en diferentes contextos --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/es/blog/laravel/laravel-middleware-deep-dive