Hey guys,
This has been one of the most frustrating issues I've had with Laravel (and I'm not the only one).
Thanks God I found what caused it.
Since 5.2
we had to put all routes that required sessions in the web
middleware group. However since 5.2.27
all routes are registered in the web
middleware group by default. You would have to load another routes file with the RouteServiceProvider
if you want them registered outside the web
middleware group or remove the web
middleware group from the RouteServiceProvider
and register them manually again just like before 5.2.27
.
Now the problem is with developers who have not managed to keep up with all the latest changes in Laravel and they don't know that routes are registered by default in the web
middleware group. So they put all their routes that require sessions in the web
middleware group manually, expecting the old behaviour (before 5.2.27
).
And now the inevitable weirdest thing happens no matter the sessions driver being used:
This issue occurs because we have the web
middleware group registered twice. So to fix this, we have to check when the middleware is registered that it was not previously registered somewhere else in the middleware stack. Normally you would not end up in this situation by manually assigning middleware in the routes file, but because this is done by default on new projects by the RouteServiceProvider
and developers don't know about it, it just happens! And besides this, I find it a good check to have.
I was talking with someone on Slack who experienced the same behaviour and he was not able to work on his new project for two days because of this issue, just like me.
I've been struggling with this problem for 2 days so far and just found a solution which is not really documented.
Change the defination of your Route groups with a middleware, from :
Route::group(['middleware' => 'web'], function () {
to
Route::group(['middlewareGroups' => 'web'], function () {
then your sessions and middlewares will work as expected.
@eness While you can do that (haven't tested), I would not recommend it, because you will create the impression in your app that routes outside the web
middleware group don't have sessions enabled, when in fact they do.
As stated above, you got two options:
routes.php
file which routes belong to the web
middleware group you have to remove the web
middleware from here.routes.php
file will have the web
middleware applied. If you have routes which you don't want to have the web
middleware group applied, you can create another routes file and register it in the RouteServiceProvider
.After a closer thinking on the matter and seeing @eness response I realised that we should really not implement such a check. In my opinion at least, it will do more bad than good on the long term. Why? It creates the impression that middleware registered upper in the stack is not applied on routes where you re-register it. For this particular issue for example, it will create the impression that routes outside the web
middleware group will not have it applied and they will not have sessions enabled or the rest of the web
middleware stack, when in fact this is not true and all routes will have the web
middleware group applied and session enabled along with all the web
middleware stack.
So I will go ahead and close this issue now. I'm glad I wrote it, because developers will now be able to only search the issues to find the answer and get it right and not spend precious time thinking in the abyss.
I also experienced this issue for 2 days, and I found following make sense:
Stuck on this issue and absolutely nothing works. Is anyone having any luck?
I even tried adding StartSession to the global middleware stack and the sessions are still not persisting after redirecting from a login/register.
@Frisbetarian follow my suggestion, it should work.
Thanks for the explanation, I was tearing my hair out with this issue. I'm not entirely sure how something like this can be part of a minor update.
This was also causing very strange behavior which was override custom trusted proxies that I had set. Removing the explicit web middleware from my routes.php file solved it. Frustrating that breaking changes like this occur in minor releases.
I have the same issue, tried removing the web middleware from routes, but the issue still occurring. Been struggling with this issue for a long time, done many researches with no benefit. Any recommendations?
You might try editing App/Providers/RouteServiceProvider
The bottom of it is:
protected function mapWebRoutes(Router $router)
{
$router->group([
'namespace' => $this->namespace, 'middleware' => 'web',
], function ($router) {
require app_path('Http/routes.php');
});
}
Which I think is what changes the middleware so you could take out the 'middleware' => 'web' part and I think it would revert to the old behavior.
I am experiencing issues as described by @danieliancu in the original post. Sessions don't seem to persist, and session files are visibly generated within the storage/framework/sessions file with each HTTP request.
I've tried:
No matter what I do, the net effect of this is always one of the following:
Naturally, this makes it impossible to do any user authentication. Not sure how to fix this... Help would be appreciated!
"php artisan --version" outputs:
"Laravel Framework version 5.2.45"
@kohloth , you should not wrap any route within web middleware group in your routes.php file since this is done by laravel by default. If you remove the wrapper of Route::group(['middleware' => 'web'], it should work
I had the same problems like @kohloth in Laravel 5.3.29. I got them sorted by moving the contents of the web middleware in Kernel.php to the overall middleware array.
Before:
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
After:
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,**
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
],
'api' => [
'throttle:60,1',
],
];
Sounds to me like something was messed up in your routes file or you RouteServiceProvider. The web routes should be in /routes/web.php
.
Moving the middleware will mess you up if you try to use API routes later. If you don't use API routes, it'll be ok, but they may not work right if you try to use them later with this setup.
/app/Providers/RouteSerivceProvider.php
should look like this:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
//
parent::boot();
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapWebRoutes();
$this->mapApiRoutes();
//
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::group([
'middleware' => 'web',
'namespace' => $this->namespace,
], function ($router) {
require base_path('routes/web.php');
});
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::group([
'middleware' => 'api',
'namespace' => $this->namespace,
'prefix' => 'api',
], function ($router) {
require base_path('routes/api.php');
});
}
}
@loren138 This didn't quite work for me. Using this code in the Route Service Provider threw an error about overridden methods being incompatible with those of the parent class. I wonder if its because this code is not compatible with version 5.2.45.
After some further investigation, I believe that I have solved the issue. I was trying to log users in via AJAX. I experimented with a more typical POST login form, and it works. However, I still need to find out what the framework is doing that causes AJAX login requests to be ephemeral; working initially, but causing subsequent HTTP requests disregard this prior, successful login.
// On ajax HTTP request
Auth::attempt($username, $password);
$User = Auth::user();
var_dump($User);
// Outputs user object - login worked!
//...then on next Http request
$User = Auth::user();
var_dump($User);
// Outputs null - like login never happened. Most likely session data not stored previously.
EDIT: Found the answer to the issue here:
http://stackoverflow.com/questions/23536877/laravel-4-persisting-data-ongoing-jquery-ajax-submit
To make the session persist, when performing an AJAX login, you must replace:
echo json_encode($array);
with:
return Response::json($array);
Ah, sorry, I posted the 5.3.x version of that file not 5.2.
That's interesting about using the response object and a good fact to know for the future for me.
@kohloth Check yours routes for php artisan route:list
command all route is web midleware.
I'm fix same problems with project laravel 5.4.15 upragate.
Hi guys, i have a problem with validation errors, basically i validate required fields and is like it works but it doesn't render the errors on the page.
here my code
public function Store(Request $request)
{
$this->validate($request, [
'title' => 'required',
'body' => 'required'
]);
$post = new Post;
$post->title = request('title');
$post->body = request('body');
$post->save();
return redirect('/');
}
and here the view
@extends ('layout')
@section ('content')
<ul>
<h2>Posts</h2>
<br><br>
<a href="/posts/create">New Post</a>
<br><br>
@foreach($posts as $post)
<li>
<h3><a href="/posts/{{$post->id}}">{{ $post->title }}</a></h3>
<p>{{ $post->body }}</p>
</li>
@endforeach
</ul>
<div class="alert alert-danger">
<ul>
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endsection
if i dd the request i see this in the shared property
#shared: array:3 [
"__env" => Factory {#90}
"app" => Application {#3}
"errors" => ViewErrorBag {#163
#bags: []
}
]
@baxterw3b I believe that this is your problem:
return redirect('/');
If I am not mistaken, the error variables only persist for the current request. They are not flashed to the session. Therefore, doing a redirect will effectively delete the errors. Try this:
return redirect('/')->withErrors()
I tried but it doesn't work, and btw that redirect it happen when the user pass the validation, i don't know is really weird.
I'm putting my routes in the web.php, could be that it doesn't use the middleware for the validation?
ahahha i found the error, i think yesterday i was to tired, basically i was echoing out the errors in the wrong view! LOL. thank you man.
Hello I have the similar problem but i don't understand how to solve it.
After login, i put an object in session.
Then in my custom middleware i want to use this object but it's empty.
My web.php :
Route::get('/shareaccess/{albumid}/{shareid}', 'ShareAccessController@show')->name('shareaccess');
Route::post('/shareaccess/{albumid}/{shareid}/validate', 'ShareAccessController@login')->name('loginshareaccess');
Auth::routes();
// Main Route After Authentification
Route::get('/home', 'AlbumController@home')->name('home');
//Album Routes`
Route::get('/album/{albumid}', 'AlbumController@index')->name('album');
My kernel.php
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
// Dev tools for debugging
\Clockwork\Support\Laravel\ClockworkMiddleware::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
//note that all route specified in web.php applies this middleware
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class, //https://kfirba.me/blog/the-undocumented-authenticatesession-middleware-decoded
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\IsShare::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'is_admin' => \App\Http\Middleware\IsAdmin::class,
];
My MiddleWare IsShare.php
public function handle($request, Closure $next)
{
log::debug('ShareMiddleware : user : ' . \Auth::user());
if (\Auth::user()) {
if(\Auth::user()->isShare()) {
$share = Session::get('share');
//do some stuff
return $next($request);
}
}
return $next($request);
}
My Controller : shareaccess.php
public function show($albumid, $shareid, Request $request)
{
log::debug('ShareAccessController show : albumid : ' . $albumid . ' shareid : ' . $shareid);
return view('auth.shareaccess', ['albumid' => $albumid, 'shareid' => $shareid]);
}
public function login($albumid, $shareid, Request $request)
{
$this->validate($request, [
'email' => ['required', 'email'],
]);
$album = Album::find($albumid);
log::debug('ShareAccessController login : albumid : ' . $albumid);
$share = $album->shares()-> where('id', $shareid)->where('email', $request->email)->first();
if ($share) {
log::debug('ShareAccessController login : share found : ' . $share->email . ' ' . $share->active );
$user = User::where('email', '[email protected]')->first();
Auth::loginUsingId($user->id);
log::debug('ShareAccessController : login : user authenticated : ' . Auth::user()->email);
Session::put('share', $share);
log::debug('ShareAccessController login : share in Session : ' . Session::get('share'));
}
log::debug('validateshare : route : ' . route('album', ['albumid' => $albumid]));
return redirect()->route('album', ['albumid' => $albumid]);
// return redirect()->back();
}
Hi Everyone,
Subject: Value in a Session variable gets changed on random but not all instances.
My environment uses Laravel framework with a single MSSQL Database is used as the Session and Application database driver. A single database driver (connection) is used by the application.
The web server and the database server are on different virtual machines. Both the server runs on CentOS (Linux variant) operating system.
A master web page has a list or IDs. Clicking an ID opens the 2nd detail web page which makes an AJAX request to a REST API. The REST API invokes an external Web Service that is hosted on a different network. The AJAX call sometimes completes faster and provides the response to the caller function, but in few cases takes more time to complete.
The web page and the REST API are part of the same application and hosted in the same server instance. The application is not load-balanced.
When the user visits the master web page and click the record having ID as 1, the ID session variable is first programmatically assigned a value of 1 and then the AJAX call is made. When the user moves back to the master web page and click the record having ID as 2, the ID session variable is programmatically reassigned a value of 2. When we retrieve the value of the ID session variable, we get 2, as expected.
However, only in the cases when the AJAX call takes more time to complete, even though we programmatically reassigned a value of 2 to the ID session variable, on retrieving it, we in occasions get a value of 2 (expected value) and in other occasions we get a value of 1 (unexpected, previous value).
We are not sure whether the reassignment of the session variable was not committed or rolled back for any reason.
We are also not sure whether it is to do with any specific version of PHP, Laravel, MS SQL Server, etc, which we don鈥檛 think so.
Can anyone throw some pointers on why the value after the session reassignment is not the new value, but still the old value?
Did you set a time out for the request? The only thing that comes to my mind is that because you set the value programmatically in the beginning maybe it rollback to that when the request take longer to complete and times out.
It's not timing out, request in running at the background meanwhile the user navigating to another page and picks up another record (2). When half information loaded in UI for the second record suddenly the session value is changed to 1. The Ajax call made for the 1st record is returning value now and also the session value is changed from 2 to 1.
Please help.
Most helpful comment
I've been struggling with this problem for 2 days so far and just found a solution which is not really documented.
Change the defination of your Route groups with a middleware, from :
Route::group(['middleware' => 'web'], function () {
to
Route::group(['middlewareGroups' => 'web'], function () {
then your sessions and middlewares will work as expected.