Middleware en Laravel 11: Una Guía Completa


Victor Arana Flores

06 Aug 2024

Introducción al Middleware en Laravel 11

El middleware en Laravel 11 proporciona un mecanismo conveniente para inspeccionar y filtrar las solicitudes HTTP que ingresan a su aplicación. Por ejemplo, Laravel incluye un middleware que verifica si el usuario de su aplicación está autenticado. Si el usuario no está autenticado, el middleware lo redirigirá a la pantalla de inicio de sesión de su aplicación. Sin embargo, si el usuario está autenticado, el middleware permitirá que la solicitud continúe más allá en la aplicación.

Definición de Middleware en Laravel 11

Para crear un nuevo middleware en Laravel 11, use el comando Artisan make:middleware:

php artisan make:middleware EnsureTokenIsValid

Este comando colocará una nueva clase EnsureTokenIsValid dentro del directorio app/Http/Middleware. En este middleware, solo permitiremos el acceso a la ruta si el token suministrado coincide con un valor específico. De lo contrario, redirigiremos a los usuarios de nuevo al URI /home:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureTokenIsValid
{
    public function handle(Request $request, Closure $next): Response
    {
        if ($request->input('token') !== 'my-secret-token') {
            return redirect('/home');
        }

        return $next($request);
    }
}

Como puede ver, si el token dado no coincide con nuestro token secreto, el middleware devolverá una redirección HTTP al cliente; de lo contrario, la solicitud se pasará más allá en la aplicación.

Middleware y Respuestas en Laravel 11

Un middleware en Laravel 11 puede realizar tareas antes o después de pasar la solicitud más allá en la aplicación. Por ejemplo, el siguiente middleware realizaría una tarea antes de que la solicitud sea manejada por la aplicación:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class BeforeMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        // Realizar acción

        return $next($request);
    }
}

Mientras que este middleware realizaría su tarea después de que la solicitud sea manejada por la aplicación:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class AfterMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        // Realizar acción

        return $response;
    }
}

Registro de Middleware en Laravel 11

Middleware Global en Laravel 11

Si desea que un middleware se ejecute durante cada solicitud HTTP a su aplicación en Laravel 11, puede agregarlo a la pila de middleware global en el archivo bootstrap/app.php de su aplicación:

use App\Http\Middleware\EnsureTokenIsValid;

->withMiddleware(function (Middleware $middleware) {
    $middleware->append(EnsureTokenIsValid::class);
})

Asignación de Middleware a Rutas en Laravel 11

Si desea asignar middleware a rutas específicas en Laravel 11, puede invocar el método middleware al definir la ruta:

use App\Http\Middleware\EnsureTokenIsValid;

Route::get('/profile', function () {
    // ...
})->middleware(EnsureTokenIsValid::class);

Puede asignar varios middleware a la ruta pasando un arreglo de nombres de middleware al método middleware:

Route::get('/', function () {
    // ...
})->middleware([First::class, Second::class]);

Exclusión de Middleware en Laravel 11

Al asignar middleware a un grupo de rutas, ocasionalmente puede necesitar evitar que el middleware se aplique a una ruta individual dentro del grupo. Puede lograr esto usando el método withoutMiddleware:

use App\Http\Middleware\EnsureTokenIsValid;

Route::middleware([EnsureTokenIsValid::class])->group(function () {
    Route::get('/', function () {
        // ...
    });

    Route::get('/profile', function () {
        // ...
    })->withoutMiddleware([EnsureTokenIsValid::class]);
});

También puede excluir un conjunto de middleware de un grupo entero de definiciones de rutas:

use App\Http\Middleware\EnsureTokenIsValid;

Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () {
    Route::get('/profile', function () {
        // ...
    });
});

Grupos de Middleware en Laravel 11

A veces puede querer agrupar varios middleware bajo una sola clave para hacer que sea más fácil asignarlos a rutas en Laravel 11. Puede lograr esto usando el método appendToGroup dentro de su archivo bootstrap/app.php:

use App\Http\Middleware\First;
use App\Http\Middleware\Second;

->withMiddleware(function (Middleware $middleware) {
    $middleware->appendToGroup('group-name', [
        First::class,
        Second::class,
    ]);
})

Los grupos de middleware pueden asignarse a rutas y acciones del controlador usando la misma sintaxis que los middleware individuales:

Route::get('/', function () {
    // ...
})->middleware('group-name');

Route::middleware(['group-name'])->group(function () {
    // ...
});

Alias de Middleware en Laravel 11

Puede asignar alias a los middleware en Laravel 11 dentro de su archivo bootstrap/app.php. Los alias de middleware permiten definir un alias corto para una clase de middleware dada, lo que puede ser especialmente útil para middleware con nombres de clase largos:

use App\Http\Middleware\EnsureUserIsSubscribed;

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'subscribed' => EnsureUserIsSubscribed::class
    ]);
})

Una vez que el alias del middleware se ha definido en el archivo bootstrap/app.php de su aplicación, puede usar el alias al asignar el middleware a las rutas:

Route::get('/profile', function () {
    // ...
})->middleware('subscribed');

Ordenación de Middleware en Laravel 11

En raras ocasiones, es posible que necesite que su middleware se ejecute en un orden específico en Laravel 11 pero no tener control sobre su orden cuando se asignan a la ruta. En estas situaciones, puede especificar la prioridad de su middleware usando el método priority en su archivo bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->priority([
        \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
        \Illuminate\Cookie\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class,
        \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ]);
})

Parámetros de Middleware en Laravel 11

El middleware en Laravel 11 también puede recibir parámetros adicionales. Por ejemplo, si su aplicación necesita verificar que el usuario autenticado tenga un determinado "rol" antes de realizar una acción dada, podría crear un middleware EnsureUserHasRole que reciba un nombre de rol como argumento adicional:

<?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 $role): Response
    {
        if (!$request->user()->hasRole($role)) {
            // Redirigir...
        }

        return $next($request);
    }
}

Los parámetros adicionales del middleware se pasarán al middleware después del argumento $next:

Route::put('/post/{id}', function (string $id) {
    // ...
})->middleware('role:editor');

Múltiples parámetros pueden delimitarse con comas:

Route::put('/post/{id}', function (string $id) {
    // ...
})->middleware('role:editor,publisher');

Middleware Terminable en Laravel 11

A veces un middleware en Laravel 11 puede necesitar hacer algún trabajo después de que la respuesta HTTP haya sido enviada al navegador. Si define un método terminate en su middleware y su servidor web está usando FastCGI, el método terminate se llamará automáticamente después de que la respuesta haya sido enviada al navegador:

<?php

namespace Illuminate\Session\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class TerminatingMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        return $next($request);
    }

    public function terminate(Request $request, Response $response): void
    {
        // ...
    }
}

El método terminate debe recibir tanto la solicitud como la respuesta. Una vez que haya definido un middleware terminable, debe agregarlo a la lista de rutas o middleware globales en su archivo bootstrap/app.php.

Al llamar al método terminate en su middleware, Laravel resolverá una nueva instancia del middleware desde el contenedor de servicios. Si desea usar la misma instancia del middleware cuando se llaman los métodos handle y terminate, registre el middleware con el contenedor usando el método singleton del contenedor. Normalmente esto debería hacerse en el método register de su AppServiceProvider:

use App\Http\Middleware\TerminatingMiddleware;

public function register(): void
{
    $this->app->singleton(TerminatingMiddleware::class);
}

Con esta guía completa sobre middleware en Laravel 11, ahora tiene una comprensión clara de cómo crear, registrar y usar middleware en su aplicación. El middleware es una herramienta poderosa para manejar solicitudes HTTP y garantizar que su aplicación funcione de manera segura y eficiente.


0 comentarios

Inicia sesión para comentar