Crear Signed Routes en Laravel
Las URL’s firmadas (Signed URL’s) son un mecanismo de consulta ‘autenticada’ por medio de un string, tienen una firma (encriptada) que le permite a Laravel verificar que la URL no se haya modificado desde que se creó y son especialmente útiles para las rutas que son de acceso público pero necesitan una capa de protección contra la manipulación de URL.
Saber más de las Signed URL’s
Ahora, ¿Cómo podríamos usar una Signed Url?
Supongamos que tenemos un evento y que necesitamos enviar un correo a nuestros usuarios para que confirmen si pueden asistir o no. Lo más probable es crear una ruta que reciba el id del evento al que hacemos referencia, el id del usuario al que vamos a enviar el correo y una respuesta (si o no) para manejar ese registro:
Route::get('event/{id}/{user}/{response}',
function ($id, $user, $response) {
// Add response from user for event.
})->name('event.confirm');
Y para generar la ruta usaríamos algo como esto:
Url::route('event.confirm', ['id' => 2, 'user' => 34, 'response' => 'yes']);
Lo cual generaría algo como:
http://myproject.test/event/2/34/yes
¿Qué pasaría si un curioso y malicioso usuario cambia alguna variable como el id del usuario?
Suplantaría cualquier otro usuario confirmando la asistencia al evento y esto afectaría la integridad de nuestra información y no es lo ideal.
Firmando una URL
Primero aseguremonos de actualizar la versión de Laravel, pues esta funcionalidad sólo está disponible desde la versión 5.6.12 Release
composer update laravel/framework
Después tendremos que añadir esta linea a nuestro Route Middleware en /app/Http/Kernel.php
protected $routeMiddleware = [
// ...
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
+ 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}
Con eso ya podemos firmar url’s sin problema.
Lo primero que necesitaremos es firmar nuestra ruta con el Middleware signed
Route::get('event/{id}/{user}/{response}', function ($id, $user, $response) {
// Add response from user for event.
})->name('event.confirm')->middleware('signed');
Luego vamos a cambiar Url::route() por Url::signedRoute()
Url::signedRoute('event.confirm', ['id' => 2, 'user' => 34, 'response' => 'yes']);
Laravel generará una url firmada para evitar algun tipo de daño a la integridad de la información
http://myproject.test/event/2/34/yes?
signature=30a3877b00890fff0d7ca25f82c6387ff16a98d21008ddc9689ed3c20ef13cd4
Ahora si un usuario intenta cambiar el id del usuario de 2 a 5 Laravel generará una excepción Illuminate\Routing\Exceptions\InvalidSignatureException
Url’s Temporales
Adicionalmente Laravel provee de una funcionalidad para agregar un tiempo de vencimiento de la url firmada, esto es muy útil para nuestro ejemplo, puesto que no es lógico que podamos confirmar un evento después de que haya sido ejecutado.
URL::temporarySignedRoute('event.confirm', now()->addMonth(), [
'id' => 2,
'user' => 34,
'response' => 'yes'
]);
Esta es la url generada
http://myproject.test/event/2/34/yes?
expires=1521543365
&signature=d32f53ced4a781f287b612d21a3b7d3c38ebc5ae53951115bb9af4bc3f88a87a
Aprender más
Si quieres profundizar un poco más puedes leer la documentación de Laravel Signed Url y el Api Documentation