Auth过滤器重定向回Laravel中的原始POST请求 [英] Auth filter redirecting back to original POST request in Laravel

查看:178
本文介绍了Auth过滤器重定向回Laravel中的原始POST请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎Redirect :: guest('login')仅适用于GET请求。 IE浏览器。它会将经过身份验证的用户重定向到原始目标URL(GET)。



在有POST请求的情况下,是否有一种方法可以让auth过滤器继续在用户成功登录后POST到URL?



一个简单的例子:我想显示一个可供任何人查看的表单。点击提交按钮后,auth过滤器将启动,这将使访客进入登录页面。验证成功后,我希望提交请求(即POST请求)继续进行。

解决方案

我有同样的愿望使用原始输入重定向回POST请求。除了通过GET重定向到预期的URL之外,我找不到现有的方法在Laravel中执行此操作。



Laravel 5



我首先在Laravel 4中按照下面的大纲解决了这个问题,但发现完全相同的设置无法在Laravel 5中工作。按照Laravel 4的大纲,而不是创建IntendedUrlServiceProvider创建一个中间件。


  1. 问题是,在Laravel 5中,会话似乎是在所有ServiceProviders之后运行的StartSession开始的。

/app/Http/Middleware/IntendedUrl.php

 < ;?php命名空间App \Http \中间件; 

使用Closure;
使用请求;
使用Session;

class IntendedUrl {

/ **
*这会加载已保存的POST输入数据,如果访问者试图访问某个页面,则会将该方法更改为POST
*但是通过auth过滤器阻止了。 Auth过滤器通过Redirect :: guest()保存数据,在
* login之后需要重新填充以模拟POST。
*
* GET请求也可以通过此处传递。我不太确定它是否需要它们但不应该损害
*并且可能有助于加载任何输入数据。
*
* @param \Illuminate \Http\Request $ request
* @param \Closure $ next
* @return mixed
* /
公共函数句柄($ request,Closure $ next)
{
//检查我们是否使用Redirect :: intention()重定向到此页面。
//我们扩展了类以跟踪何时发生重定向,因此我们知道重新加载其他请求数据
if(Session :: has('intention.load')){
// expected如果我们被重定向到默认页面,则可以设置.load,如果我们被重定向到默认页面
//如果存在,则两者都应该存在但是单独检查是安全的
if(Session :: has('that。方法')){
Request :: setMethod(Session :: get('intention.method'));
}
if(Session :: has('intention.input')){
Request :: replace(Session :: get('intention.input'));
}
//删除为跟踪预期请求而创建的所有会话密钥
Session :: forget('intention');

// Laravel 5.2+使用单独的全局和路由中间件。当路由类型发生变化时,发送更改的请求。 *在以下答案中信用Munsio
返回\ Route :: dispatch($ request);
}

返回$ next($ request);
}

}




  1. 然后在下面的步骤4中添加IntendedUrlServiceProvider而不是在/app/Http/Kernel.php的$ middleware数组中的StartSession之后添加新的中间件



  protected $ middleware = [
'LIuminate\Foundation\Http\Middleware\CheckForMaintenanceMode' ,
'LIuminate\Cookie\Middleware \EncryptCookies',
'Iluminate \'Cookie \ Middleware \ AdddQueuedCookiesToResponse',
'LIuminate\Session \ Middleware \StartSession ',
'LIuminate \ View \ Middleware \ ShareErrorsFromSession',

'App\Http\Middleware \IntendedUrl',
];




  • 另外值得注意的是,仅仅是为了组织我移动了我的客户服务提供商新标准/应用/提供商并更改了他们的名称空间。



Laravel 4



<我决定扩展框架以添加此功能。我很难详细说明我的完整解决方案,但这里有一个大纲。要做到这一点,您需要非常熟悉框架并阅读如何扩展它。
http://laravel.com/docs/extending#ioc-based-延期



我还引用了Taylor的书从学徒到工匠的Laravel


  1. 扩展Redirector类以记录预期请求的其他信息。

     <?php namespace GQ \路由; 
    类重定向器扩展\Illuminate\Routing \ Redirector {
    / **
    * **扩展为添加POST输入和POST方法后登录
    的功能* /
    公共函数guest($ path,$ status = 302,$ headers = array(),$ secure = null)
    {
    //记录请求的方法和输入它可以在重定向回到目标页面后重新加载$ ​​b $ b $ this-> session-> put('intention.method',$ this-> generator-> getRequest() - > getMethod ());
    $ this-> session-> put('intention.input',$ this-> generator-> getRequest() - > all());

    返回parent :: guest($ path,$ status,$ headers,$ secure);
    }

    / **
    * **当我们重定向到目标页面时扩展到会话中记录,因此可以在下一页加载方法和输入
    * /
    预期的公共函数($ default ='/',$ status = 302,$ headers = array(),$ secure = null)
    {
    $ redirect_response = parent ::预期的($ default,$ status,$ headers,$ secure);

    //设置intention.load会话变量,以便我们知道我们返回到目标页面并可以加载其他方法并输入
    return $ redirect_response-> with('intention.load ',真实);
    }
    }
    ?>


  2. 创建一个新的服务提供者,在IOC容器中写入redirect。我最初尝试扩展RoutingServiceProvider,但遇到了麻烦。

     <?php namespace App \ Provider; 

    使用GQ \Routing \ Redirector;
    使用Illuminate\Support\ServiceProvider;
    class RedirectServiceProvider扩展ServiceProvider {

    protected $ defer = true;

    / **
    *注册重定向器服务。
    *
    * **来自RoutingServiceProvider的类registerRedirector的副本,
    *在顶部使用不同的use语句来使用扩展的重定向器类
    *扩展RoutingServiceProvider更多因为它作为应用程序中的基本提供者加载而做的很痛苦
    *
    * @return void
    * /
    公共函数寄存器()
    {
    $ this-> app ['redirect'] = $ this-> app-> share(功能($ app)
    {
    $ redirector = new Redirector($ app [ 'url']);

    //如果在应用程序实例上设置会话,我们会将其注入
    //重定向器实例。这允许重定向响应允许
    //用于非常方便的with方法闪现到会话。
    if(isset($ app ['session.store']))
    {
    $ redirector- > setSession($应用['session.store ]);
    }

    $返回重定向器;
    });
    }
    公共函数提供(){
    返回数组('redirect');
    }
    }


  3. 创建一个新的服务提供商,它将设置重定向后的预期方法和输入。

     <?php 

    名称空间GQ \提供者;

    使用Illuminate\Support\ServiceProvider;

    类IntendedUrlServiceProvider扩展ServiceProvider {
    / **
    *引导应用程序事件。
    *
    * @return void
    * /
    public function boot(){
    //检查我们是否使用Redirect重定向到此页面::意()。
    //我们扩展了类以跟踪何时发生重定向,因此我们知道重新加载其他请求数据
    if(\ Session @ ::('intent.load')){
    /如果我们被重定向到默认页面,则可以设置/ intention.load设置为
    //如果存在,则两者都应该存在但是单独检查是安全的
    if(\ Session @ :: ('intention.method')){
    \Request :: setMethod(\Session :: get('intention.method'));
    }
    if(\ _Session :: has('intention.input')){
    \Request :: replace(\Session :: get('intention.input') );
    }
    //删除为跟踪预期请求而创建的所有会话密钥
    \Session :: forget('intention');
    }
    }

    公共函数寄存器(){
    }
    }


  4. 最后在app / config / app.php中将您的2个新服务提供商添加到您的提供者数组

     'GQ \Providers \ RedirectServiceProvider',
    'GQ\Providers \IntendedUrlServiceProvider',


希望这会引导你朝着一个好方向前进。这对我有用,但我还没有广泛测试过。也许如果它继续运作良好,我们可以建立一个作曲家包或获得Laravel中包含的能力。


It seems that Redirect::guest('login') will only work for GET requests. Ie. it will redirect an authenticated user to the original intended URL (GET).

In a situation where there is a POST request, is there a way for the auth filter to continue on to POST to a URL after the user has successfully logged on?

A simple example: I want to show a form available to anyone to view. Upon hitting the submit button, the auth filter kicks in which will bring a guest to the login page. After successful authentication, I would like the submit request (ie. POST request) to continue onwards.

解决方案

I had the same desire to redirect back to a POST request with the original input. I could not find an existing way to do this in Laravel except for redirecting to to the intended URL via GET.

Laravel 5

I first solved this in Laravel 4 following the outline below but found the exact same setup not to work in Laravel 5. Follow the outline for Laravel 4 but instead of the creating the IntendedUrlServiceProvider create a Middleware.

  1. The problem is that in Laravel 5 the session seems to be started with the StartSession which runs after all of the 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);
    }

}

  1. Then instead of adding the IntendedUrlServiceProvider as in step 4 below add the new middleware after the StartSession in the $middleware array of /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',
];

  • Also of note, just for organization I moved my customer service providers to the new standard /App/Providers and changed their namespace.

Laravel 4

I decided to extend the framework to add this feature. It will be hard to detail my complete solution, but here is an outline. To do this you will need to be pretty familiar with the framework and read up on how to extend it. http://laravel.com/docs/extending#ioc-based-extension

I also referenced Taylor's book "Laravel from Apprentice to Artisan"

  1. Extend the Redirector class to record additional info on the intended request.

    <?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);
        }
    }
    ?>
    

  2. Create a new Service Provider that writes over "redirect" in the IOC container. I originally tried extending the RoutingServiceProvider but had trouble with that working.

    <?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');
        }
    }
    

  3. Create a new service provider which will set the intended method and input after the redirect.

    <?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() {
        }
    }
    

  4. Finally add your 2 new service providers to your providers array in app/config/app.php

    'GQ\Providers\RedirectServiceProvider',
    'GQ\Providers\IntendedUrlServiceProvider',
    

Hopefully this steers you in a good direction. This has worked for me but I have not tested it extensively. Maybe if it continues to work well we could build a composer package or get the ability included in Laravel.

这篇关于Auth过滤器重定向回Laravel中的原始POST请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆