Laravel 5 null cookie崩溃

时间:2015-09-04 15:35:25

标签: php laravel

情景:

相同的浏览器。

  1. 选项卡1:登录我的laravel应用程序。
  2. 选项卡2:登录我的laravel应用程序。
  3. 标签2:注销
  4. 选项卡1:点击一个按钮,该按钮会导致重定向到受以下路由保护的路由:Route :: group([' middleware' =>' auth'] ,function(){ ...
  5. 结果:Laravel 5在到达我的代码之前崩溃:

    enter image description here

    堆栈:

    Symfony\Component\Debug\Exception\FatalErrorException Call to a member function setCookie() on null
        vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:184 __construct
        vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:131 fatalExceptionFromError
        vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:116 handleShutdown
        vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:0 addCookieToResponse
        vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:72 handle
        vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:125 Illuminate\Pipeline\{closure}
        vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php:36 handle
        vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:125 Illuminate\Pipeline\{closure}
        vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php:40 handle
        vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:125 Illuminate\Pipeline\{closure}
        vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php:42 handle
        vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:125 Illuminate\Pipeline\{closure}
        vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:101 call_user_func:{/home/vagrant/dev/opus-web-app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:101}
        vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:101 then
        vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:115 sendRequestThroughRouter
        vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:84 handle
        public/index.php:53 {main}
        public/index.php:0 [main]
    

    即使我从我的路线中删除了Route :: group(['中间件' =>' auth']组...在标签1中转到现在打开的网址会产生这个错误。我只是没有得到它。

    我如何摆脱这个?

3 个答案:

答案 0 :(得分:3)

我找出原因,但我不确定。希望你们其中一个人知道。

在kernel.php中:

我在'App\Http\Middleware\VerifyCsrfToken'黑色而不是$middleware中定义了$routeMiddleware。当我把它移到$routeMiddleware时,我停止了那个错误。

VerifyCsrfToken的内容:

class VerifyCsrfToken extends BaseVerifier {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request && (($this->isReading($request) || $this->excludedRoutes($request) || ($this->tokensMatch($request) && Auth::check()))))
        {
            return $this->addCookieToResponse($request, $next($request));
        }

        return view('sessionOver');
    }

    protected function excludedRoutes($request)
    {
        $routes = [
            'deployPush'  // webhook push for bitBucket.
        ];

        foreach($routes as $route)
            if ($request->is($route))
                return true;

        return false;
    }
}

答案 1 :(得分:0)

在我看来,问题是你在检查CSRF时的逻辑。

问题在于: 您正在检查令牌是否匹配,该功能如下:

protected function tokensMatch($request)
{
    $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');

    if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
        $token = $this->encrypter->decrypt($header);
    }

    return Str::equals($request->session()->token(), $token);
}

但是如果你仔细观察,你会看到它在回报中检查:

$request->session()->token()

但是,会话为null,因此您尝试从null请求方法时会遇到异常。

因此,如果我没有弄错的话,您只需要在handle方法中为if添加额外的检查。 而不是:

if ($request && ((
      $this->isReading($request) 
      || $this->excludedRoutes($request) 
      || ($this->tokensMatch($request) && Auth::check())
    )))

你应该有这个:

if ($request && ((
      $this->isReading($request) 
      || $this->excludedRoutes($request) 
      || ($request->hasSession() && $this->tokensMatch($request) && Auth::check())
   )))

这样,如果没有会话,它甚至不会检查令牌是否匹配,并且它不会在那里崩溃。

您也可以考虑将if语句的一部分重构为一个函数,该函数按名称描述您要检查的内容,甚至是完整的if语句,该函数说明了所有内容。仅为了清晰的代码。

是其中之一,或者您可以考虑检查您的其他中间件,任何触及请求标头的人,并且可能会取消设置标题。

如果您使用StartSession中间件的handle功能代码:

public function handle($request, Closure $next)
{
    $this->sessionHandled = true;
    if ($this->sessionConfigured())
    {
        $session = $this->startSession($request);
        $request->setSession($session);
    }

    // ** HERE ALL OTHER MIDDLEWARES ARE BEING CALL
    $response = $next($request);

    if ($this->sessionConfigured())
    {
        $this->storeCurrentUrl($request, $session);
        $this->collectGarbage($session);
        // ** AFTER ALL OTHER MIDDLEWARES ARE CALLED THE FOLLOWING FUNCTION 
        // TOUCHES THE HEADER AND IS NULL
        $this->addCookieToResponse($response, $session);
    }
    return $response;
}

因此,根据您的错误,可能会在任何其他任何中间件的某处触及标题并将其保留为空。

我希望有所帮助。

答案 2 :(得分:0)

在从中间件返回响应时经历了类似的问题,我意识到这是由返回return view('my.view.blade')而不是return response()->view('my.view.blade')引起的。

所以简而言之,不要直接返回视图。将view()助手链接到response()助手。

return view('myview.blade'); //wrong
return response()->view('myview.blade'); //works