php - tokenmismatchexception - ¿Cómo específicamente Laravel construye y verifica un token CSRF?
generar token laravel (2)
Dado que esta se ha convertido en una pregunta popular, decidí publicar mi solución específica que ha funcionado bastante bien ...
Lo más probable es que tengas un header.php o alguna vista parcial que uses en la parte superior de todas tus páginas, asegúrate de que esté en la sección <head>
:
<meta name="_token" content="<?=csrf_token(); ?>" />
En tus filtros.
Route::filter(''csrf'', function()
{
if (Request::ajax()) {
if(Session::token() != Request::header(''X-CSRF-Token'')){
throw new Illuminate/Session/TokenMismatchException;
}
}
});
Y en tus rutas .php
Route::group(array(''before'' => ''csrf''), function(){
// All routes go in here, public and private
});
Estoy usando la protección CSRF de Laravel en mi sitio público. Sin embargo, dado que Laravel usa una sesión para mantener esto, me preocupa que un usuario pueda alejarse de su computadora y regresar a una página que previamente dejó abierta, solo para encontrar que las solicitudes de ajax no funcionan. Las solicitudes de ajax no funcionan porque la sesión ha caducado (¿y el token ya no se valida?). Si estos usuarios estuvieran "conectados", entonces simplemente podría redirigirlos a la página de inicio de sesión. Como son usuarios públicos, entonces el usuario se ve obligado a actualizar la página para que vuelva a funcionar (incómodo).
¿O me equivoco sobre esto? ¿El token CSRF aún sería validado por Laravel (incluso después de que se agote el tiempo de espera, la página seguirá enviando el token ... pero qué hará Laravel con él?). Una solución óptima sería tener los tokens parcialmente basados en una marca de tiempo para que podamos establecer los límites de caducidad de los tokens aparte de los límites de tiempo de la sesión. Podría hacer que mis tokens CSRF duren 2 días (por lo que solo los usuarios que se vayan durante 2 días volverán a una página muerta).
En última instancia, esto me lleva a mi pregunta: ¿Dónde está el código específico en el marco de trabajo de Laravel que maneja esto? Actualmente estoy tratando de localizarlo. Además, ¿hay una caída fácil en el reemplazo que puedo hacer, o me quedan para crear mi propia versión de csrf_token();
para enviar a mis páginas y luego necesitaría crear mi propio filtro de ruta para ir con él.
Laravel simplemente facilita eso para usted al mantener el token almacenado en la sesión, pero el código es realmente suyo (para cambiarlo como desee). Echa un vistazo a filters.php
que deberías ver:
Route::filter(''csrf'', function()
{
if (Session::token() != Input::get(''_token''))
{
throw new Illuminate/Session/TokenMismatchException;
}
});
Nos dice que si tienes una ruta:
Route::post(''myform'', [''before'' => ''csrf'', ''uses'' => ''MyController@update'']);
Y la sesión del usuario caduca, generará una excepción, pero usted puede hacer el trabajo usted mismo, mantener su propio token almacenado donde crea que sea mejor y, en lugar de lanzar esa excepción, redirigir al usuario a la página de inicio de sesión:
Route::filter(''csrf'', function()
{
if (MySession::token() != MyCSRFToken::get())
{
return Redirect::to(''login'');
}
});
Y, sí, puedes crear tu propio csrf_token()
, solo tienes que cargarlo antes de que lo haga Laravel. Si observa el archivo helpers.php en el código fuente de Laravel, verá que solo crea esa función si no existe:
if ( ! function_exists(''csrf_token''))
{
function csrf_token()
{
...
}
}