authentication - formrequest - Auth filter redirecciona a la solicitud POST original en Laravel
request laravel (2)
En Laravel 5.2 implementaron los grupos de middleware y para los proyectos nuevos aplicaron el grupo predeterminado "web" a todo el archivo routes.php.
El problema:
Los middleware de grupo se llaman después de que se determinó la ruta, por lo que simplemente cambiar el método de la solicitud actual no tiene ningún efecto.
Hay dos enfoques diferentes para que vuelva a funcionar (sugiero nr. 2)
Solución 1:
Vuelva a colocar la sesión y el middleware de url deseado en la matriz de middleware global en el archivo Kernel.php. Eso es fácil y funcionaría, pero a veces tiene junto a su proyecto algunas rutas de REST-API y una sesión no tiene nada que hacer allí.
Solución 2:
Coloque la clase url prevista después de la clase ShareErrorsFromSession en el grupo web y adopte el archivo como se muestra a continuación:
// Erase all session keys created to track the intended request
Session::forget(''intended'');
$response = Route::dispatch($request);
return $response;
Al enviar las solicitudes modificadas, rompemos el ciclo de vida actual y llamamos a uno nuevo, para que se use la ruta correcta y funcione como se espera. El segundo enfoque nos brinda también la posibilidad de definir la funcionalidad de URL integrada solo para rutas seleccionadas si así lo desea.
Parece que Redirect :: guest (''login'') solo funcionará para solicitudes GET. Es decir. redirigirá a un usuario autenticado a la URL original prevista (GET).
En una situación en la que hay una solicitud POST, ¿hay alguna manera de que el filtro de autenticación continúe con POST a una URL después de que el usuario haya iniciado sesión correctamente?
Un ejemplo simple: quiero mostrar un formulario disponible para que cualquiera lo vea. Al presionar el botón de enviar, se inicia el filtro de autenticación que llevará a un invitado a la página de inicio de sesión. Después de la autenticación exitosa, me gustaría que la solicitud de envío (es decir, la solicitud POST) continúe en adelante.
Tenía el mismo deseo de redireccionar a una solicitud POST con la entrada original. No pude encontrar una forma existente de hacerlo en Laravel, excepto para redirigir a la URL prevista a través de GET.
Laravel 5
Primero resolví esto en Laravel 4 siguiendo el siguiente esquema pero encontré la misma configuración exacta para no trabajar en Laravel 5. Siga el esquema para Laravel 4 pero en lugar de crear IntendedUrlServiceProvider cree un Middleware.
- El problema es que en Laravel 5 parece que la sesión se inicia con la StartSession que se ejecuta después de todos los ServiceProviders.
/app/Http/Middleware/IntendedUrl.php
<?php namespace App/Http/Middleware;
use Closure;
use Request;
use Session;
class IntendedUrl {
/**
* This loads saved POST input data and changes the method to POST if a visitor tried to access a page
* but was blocked via an auth filter. Auth filter saves data via the Redirect::guest() and after
* login it needs to be repopulated to simulate a POST.
*
* GET requests also may pass through here. I am less certain if it is required for them but shouldn''t hurt
* and may help load any input data.
*
* @param /Illuminate/Http/Request $request
* @param /Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// Check to see if we were redirected to this page with the Redirect::intended().
// We extended the class to track when the redirect occurs so we know to reload additional request data
if (Session::has(''intended.load'')) {
// intended.load could be set without these being set if we were redirected to the default page
// if either exists, both should exist but checking separately to be safe
if (Session::has(''intended.method'')) {
Request::setMethod(Session::get(''intended.method''));
}
if (Session::has(''intended.input'')) {
Request::replace(Session::get(''intended.input''));
}
// Erase all session keys created to track the intended request
Session::forget(''intended'');
// Laravel 5.2+ uses separate global and route middlewares. Dispatch altered request as the route type changed. *Credit to Munsio in answer below
return /Route::dispatch($request);
}
return $next($request);
}
}
- Luego, en lugar de agregar IntendedUrlServiceProvider como en el paso 4 a continuación, agregue el nuevo middleware después de la StartSession en la matriz $ middleware de /app/Http/Kernel.php
protected $middleware = [
''Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode'',
''Illuminate/Cookie/Middleware/EncryptCookies'',
''Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse'',
''Illuminate/Session/Middleware/StartSession'',
''Illuminate/View/Middleware/ShareErrorsFromSession'',
''App/Http/Middleware/IntendedUrl'',
];
- También cabe destacar que, solo para la organización, moví mis proveedores de servicio al cliente al nuevo estándar / Aplicación / Proveedores y cambié su espacio de nombre.
Laravel 4
Decidí ampliar el marco para agregar esta característica. Será difícil detallar mi solución completa, pero aquí hay un resumen. Para hacer esto, necesitarás estar bastante familiarizado con el marco y leer sobre cómo extenderlo. http://laravel.com/docs/extending#ioc-based-extension
También mencioné el libro de Taylor "Laravel from Apprentice to Artisan"
Extienda la clase Redirector para registrar información adicional sobre la solicitud prevista.
<?php namespace GQ/Routing; class Redirector extends /Illuminate/Routing/Redirector { /** * ** Extended to add functionality for restoring POST input and the POST method after a login */ public function guest($path, $status = 302, $headers = array(), $secure = null) { // Recording the method and input for the request so that it can be reloaded after being redirected back to the intended page $this->session->put(''intended.method'', $this->generator->getRequest()->getMethod()); $this->session->put(''intended.input'', $this->generator->getRequest()->all()); return parent::guest($path, $status, $headers, $secure); } /** * ** Extended to record in the session when we redirect to an intended page so method and input can be loaded on the next page */ public function intended($default = ''/'', $status = 302, $headers = array(), $secure = null) { $redirect_response = parent::intended($default, $status, $headers, $secure); // Set the intended.load session variable so we know we returned to the intended page and can load the additional method and input return $redirect_response->with(''intended.load'', true); } } ?>
Cree un nuevo Proveedor de servicios que escriba sobre "redirigir" en el contenedor de IOC. Intenté originalmente extender el RoutingServiceProvider pero tuve problemas con ese funcionamiento.
<?php namespace App/Providers; use GQ/Routing/Redirector; use Illuminate/Support/ServiceProvider; class RedirectServiceProvider extends ServiceProvider { protected $defer = true; /** * Register the Redirector service. * * ** Copy of class registerRedirector from RoutingServiceProvider, * using a different "use" statement at the top to use the extended Redirector class * Extending the RoutingServiceProvider was more of a pain to do right since it is loaded as a base provider in the Application * * @return void */ public function register() { $this->app[''redirect''] = $this->app->share(function($app) { $redirector = new Redirector($app[''url'']); // If the session is set on the application instance, we''ll inject it into // the redirector instance. This allows the redirect responses to allow // for the quite convenient "with" methods that flash to the session. if (isset($app[''session.store''])) { $redirector->setSession($app[''session.store'']); } return $redirector; }); } public function provides() { return array(''redirect''); } }
Cree un nuevo proveedor de servicios que establecerá el método y la entrada previstos después de la redirección.
<?php namespace GQ/Providers; use Illuminate/Support/ServiceProvider; class IntendedUrlServiceProvider extends ServiceProvider { /** * Bootstrap the application events. * * @return void */ public function boot() { // Check to see if we were redirected to this page with the Redirect::intended(). // We extended the class to track when the redirect occurs so we know to reload additional request data if (/Session::has(''intended.load'')) { // intended.load could be set without these being set if we were redirected to the default page // if either exists, both should exist but checking separately to be safe if (/Session::has(''intended.method'')) { /Request::setMethod(/Session::get(''intended.method'')); } if (/Session::has(''intended.input'')) { /Request::replace(/Session::get(''intended.input'')); } // Erase all session keys created to track the intended request /Session::forget(''intended''); } } public function register() { } }
Finalmente, agregue sus 2 nuevos proveedores de servicios a su matriz de proveedores en app / config / app.php
''GQ/Providers/RedirectServiceProvider'', ''GQ/Providers/IntendedUrlServiceProvider'',
Espero que esto te guíe en una buena dirección. Esto funcionó para mí, pero no lo he probado extensivamente. Tal vez si continúa funcionando bien podríamos construir un paquete de compositores o tener la capacidad incluida en Laravel.