Reputation: 5444
Scenario:
Same browser.
Result: Laravel 5 crashes before it gets to my code on:
Stack:
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]
Even when I remove the Route::group(['middleware' => 'auth'] group from my routes... going in tab 1 to the now open URLs will produce this error. I just don't get it.
How do I get rid of this?
Upvotes: 11
Views: 3835
Reputation: 2566
Experienced a similar issue specifically when returning a response from a middleware, and I realised it was caused by returning return view('my.view.blade')
rather than return response()->view('my.view.blade')
.
So in short, don't return the view directly. Chain the view()
helper to the response()
helper.
return view('myview.blade'); //wrong
return response()->view('myview.blade'); //works
Upvotes: 0
Reputation: 1359
Seems to me that the problem is your logic in the check of the CSRF.
Here is the problem: You are checking if the tokens match, and that function is as follow:
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);
}
But if you look closely you will see that in the return it checks for:
$request->session()->token()
But, the session is null
so you will get an exception for trying to request a method from a null.
So, if I'm not mistaken, all you need to do is just to add an additional check to the if in the handle
method.
Instead of this:
if ($request && ((
$this->isReading($request)
|| $this->excludedRoutes($request)
|| ($this->tokensMatch($request) && Auth::check())
)))
You should have this:
if ($request && ((
$this->isReading($request)
|| $this->excludedRoutes($request)
|| ($request->hasSession() && $this->tokensMatch($request) && Auth::check())
)))
This way, if there is no session it will not even check if tokens match and it will not crash there.
You may also consider refactor that part of the if statement to a function that by name it describes what you are checking for, and even the complete if statement to a function that says it all. Just for code clarity.
Is either that, or you may consider checking your other Middlewares, anyone that be touching the headers of the request and potentially be unsetting the headers.
If you take at the code of the handle
function of the StartSession Middleware:
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;
}
So, it is possible that somewhere in any of any other middleware you are touching the header and leaving it null, as per your error says.
I hope that helps.
Upvotes: 0
Reputation: 8078
May be this will usefull for you .check in middleware some think similar like this
public function handle($request, Closure $next)
{
$response = $next($request);
if ( ! Auth::user()) // Your logic here...
abort(403, 'Unauthorized action.');
return $response;
}
in that discussion some cookie error discussed.that might help you
Upvotes: 0
Reputation: 5444
I figured out the cause, but I'm just not sure about it. Hoping one of you will know.
In kernel.php:
I had the 'App\Http\Middleware\VerifyCsrfToken'
defined in the $middleware
black and not the $routeMiddleware
. when I moved it to the $routeMiddleware
I stopped getting that error.
Content of 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;
}
}
Upvotes: 3