Laravel 5.6 - 会话过期后不再保留
Laravel 5.6 - Session is not persisting after it expires
我的两个本地环境有一个非常奇怪的问题。一旦我的会话由于太长时间没有刷新而过期,将按预期创建一个新会话。但是,如果我在 public 站点(不受 Auth 保护)上浏览,会话将不会持续存在,并且对于每个 get/post 请求,它将被忽略并创建一个新的(我可以在 storage/framework).
中看到 XRSF 令牌和正在创建的新文件
以下是几种情况:
如果没有用户登录,一切正常。
如果管理员用户已登录(选中 "Remember me"),但 public 用户未登录,则访问任何 public(未受保护的)路由(这使用默认 web
中间件)将如上所述重新创建会话。但是,一旦我访问 admin
中间件(web
中间件 + 验证检查)下的任何路由,会话将保持不变,之后 public 路由的问题就消失了。
如果两个用户都已登录并且我访问任何受保护的路由,会话会立即保持。
我尝试了以下方法,但没有成功:
- 阅读并尝试其他线程的建议
- 删除所有缓存
- 重新安装XAMPP
- 尝试了不同的浏览器(Chrome、Edge 和新安装的 Firefox 的结果相同)
- 设置 SESSION_DOMAIN - 这实际上破坏了 Edge,会话完全停止工作
- 已删除站点 cookie
- 已更改 APP_URL 和 APP_NAME
- 已尝试会话的文件和数据库驱动程序
- 通过 VHost(例如 http://mySite/)和通过 php artisan 服务器
使用 XAMPP 访问了站点
- 确保
web
中间件不会两次应用于任何路由
解决问题的方法:
- 正在访问受保护的页面
- 删除 cookies
- 重新打开浏览器
我重现问题的环境:
我的电脑
- Windows 10 Pro x64,内部版本 1709
- PHP7.2.0 (XAMPP)
我的笔记本电脑
- Windows 10 Pro x64,内部版本 1803
- PHP7.2.7 (XAMPP)
同事的笔记本电脑
- macOS High Sierra 10.13.6
- PHP 7.2.1 (MAMP)
可能不会导致问题的原因:
- 文件权限
- 我的 Laravel 配置(因为我在类似线程中尝试了很多建议)
- XAMPP 或 MAMP
- OS
可能导致问题的原因:
- cookies(虽然我不知道怎么做)
- PHP 设置
- Laravel(考虑到给定场景中的奇怪行为,我还不能排除这个选项)
以下是一些可能对您有用的文件:
.env
APP_NAME=MySite
APP_ENV=local
APP_KEY=base64:dEoI03jGqlhIZS4om6sx7j7aFMmKEweJpN72PijsCTQ=
APP_DEBUG=true
APP_URL=http://mySite
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=mySite
DB_USERNAME=root
DB_PASSWORD=password
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
RouteServiceProvider.php
<?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->mapApiRoutes();
$this->mapPublicRoutes();
$this->mapOrganizationRoutes();
$this->mapVolunteerRoutes();
$this->mapAdminRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapAdminRoutes()
{
Route::middleware('admin')
->prefix("admin")
->namespace($this->namespace."\Admin")
->group(base_path('routes/admin.php'));
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapPublicRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/public.php'));
}
/**
* Define the "organization" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
* It also contains auth protection and nav builder
*
* @return void
*/
protected function mapOrganizationRoutes()
{
Route::middleware('organization')
->prefix("organization")
->namespace($this->namespace . "\Organization")
->group(base_path('routes/organization.php'));
}
/**
* Define the "volunteer" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
* It also contains auth protection and nav builder
*
* @return void
*/
protected function mapVolunteerRoutes()
{
Route::middleware('volunteer')
->prefix("volunteer")
->namespace($this->namespace . "\Volunteer")
->group(base_path('routes/volunteer.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
}
routes/public.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register public routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', "LandingController@getIndex");
Route::group(["prefix" => "/auth"], function () {
Route::get('/logout/{guard}', 'Common\AuthController@getLogout')->name('logout.get');
Route::get('/login', 'Common\AuthController@getLogin')->name('login.get');
Route::post('/login', 'Common\AuthController@postLogin')->name('login.post');
Route::get('/register/{guard}', 'Common\RegistrationController@getRegister')->name('register.get');
Route::post('/register/{guard}', 'Common\RegistrationController@postRegister')->name('register.post');
Route::get("/register/success/{guard}", "Common\RegistrationController@getSuccess")->name("register.success.get");
});
Route::group(["prefix" => "admin/auth"], function() {
Route::get("/login", "Admin\AuthController@getLogin")->name("admin.auth.login.get");
Route::post("/login", "Admin\AuthController@postLogin")->name("admin.auth.login.post");
Route::get("/logout", "Admin\AuthController@getLogout")->name("admin.auth.logout.get");
});
routes/admin.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "admin" middleware group. Routes are prefixed with "/admin"
| Now create something great!
|
*/
Route::get("/", "DashboardController@getIndex")->name("admin.dashboard");
// rest omitted
Http/Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* 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,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::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\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
'admin' => [
'web',
'auth:admin',
'nav:admin', // nav is custom middleware for loading navigation config to nwidart/laravel-menus library
],
'organization' => [
'web',
'auth:organization',
'nav:organization',
],
'volunteer' => [
'web',
'auth:volunteer',
'nav:volunteer',
],
];
/**
* 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' => \App\Http\Middleware\AuthMiddleware::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'nav' => \App\Http\Middleware\NavigationBuilder::class,
];
}
AuthMiddlware.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class AuthMiddleware {
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard) {
if (!Auth::guard($guard)->check()) {
return redirect()->route(config("auth.guards.$guard.redirect"));
}
return $next($request);
}
}
为了结束这个,我想说欢迎任何建议或评论。我需要确定这是否是我的本地问题,或者这是否与 Laravel 有关,以便我可以在他们的 GitHub 页面上打开一个问题。
经过进一步调查,我发现问题是由barryvdh/laravel-debugbar包引起的。通过删除它或将应用程序变成 production/debug=false,一切都按预期工作。一旦收到 barryvdh 的回复,我将更新此答案。
我的两个本地环境有一个非常奇怪的问题。一旦我的会话由于太长时间没有刷新而过期,将按预期创建一个新会话。但是,如果我在 public 站点(不受 Auth 保护)上浏览,会话将不会持续存在,并且对于每个 get/post 请求,它将被忽略并创建一个新的(我可以在 storage/framework).
中看到 XRSF 令牌和正在创建的新文件以下是几种情况:
如果没有用户登录,一切正常。
如果管理员用户已登录(选中 "Remember me"),但 public 用户未登录,则访问任何 public(未受保护的)路由(这使用默认
web
中间件)将如上所述重新创建会话。但是,一旦我访问admin
中间件(web
中间件 + 验证检查)下的任何路由,会话将保持不变,之后 public 路由的问题就消失了。如果两个用户都已登录并且我访问任何受保护的路由,会话会立即保持。
我尝试了以下方法,但没有成功:
- 阅读并尝试其他线程的建议
- 删除所有缓存
- 重新安装XAMPP
- 尝试了不同的浏览器(Chrome、Edge 和新安装的 Firefox 的结果相同)
- 设置 SESSION_DOMAIN - 这实际上破坏了 Edge,会话完全停止工作
- 已删除站点 cookie
- 已更改 APP_URL 和 APP_NAME
- 已尝试会话的文件和数据库驱动程序
- 通过 VHost(例如 http://mySite/)和通过 php artisan 服务器 使用 XAMPP 访问了站点
- 确保
web
中间件不会两次应用于任何路由
解决问题的方法:
- 正在访问受保护的页面
- 删除 cookies
- 重新打开浏览器
我重现问题的环境:
我的电脑
- Windows 10 Pro x64,内部版本 1709
- PHP7.2.0 (XAMPP)
我的笔记本电脑
- Windows 10 Pro x64,内部版本 1803
- PHP7.2.7 (XAMPP)
同事的笔记本电脑
- macOS High Sierra 10.13.6
- PHP 7.2.1 (MAMP)
可能不会导致问题的原因:
- 文件权限
- 我的 Laravel 配置(因为我在类似线程中尝试了很多建议)
- XAMPP 或 MAMP
- OS
可能导致问题的原因:
- cookies(虽然我不知道怎么做)
- PHP 设置
- Laravel(考虑到给定场景中的奇怪行为,我还不能排除这个选项)
以下是一些可能对您有用的文件:
.env
APP_NAME=MySite
APP_ENV=local
APP_KEY=base64:dEoI03jGqlhIZS4om6sx7j7aFMmKEweJpN72PijsCTQ=
APP_DEBUG=true
APP_URL=http://mySite
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=mySite
DB_USERNAME=root
DB_PASSWORD=password
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
RouteServiceProvider.php
<?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->mapApiRoutes();
$this->mapPublicRoutes();
$this->mapOrganizationRoutes();
$this->mapVolunteerRoutes();
$this->mapAdminRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapAdminRoutes()
{
Route::middleware('admin')
->prefix("admin")
->namespace($this->namespace."\Admin")
->group(base_path('routes/admin.php'));
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapPublicRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/public.php'));
}
/**
* Define the "organization" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
* It also contains auth protection and nav builder
*
* @return void
*/
protected function mapOrganizationRoutes()
{
Route::middleware('organization')
->prefix("organization")
->namespace($this->namespace . "\Organization")
->group(base_path('routes/organization.php'));
}
/**
* Define the "volunteer" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
* It also contains auth protection and nav builder
*
* @return void
*/
protected function mapVolunteerRoutes()
{
Route::middleware('volunteer')
->prefix("volunteer")
->namespace($this->namespace . "\Volunteer")
->group(base_path('routes/volunteer.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
}
routes/public.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register public routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', "LandingController@getIndex");
Route::group(["prefix" => "/auth"], function () {
Route::get('/logout/{guard}', 'Common\AuthController@getLogout')->name('logout.get');
Route::get('/login', 'Common\AuthController@getLogin')->name('login.get');
Route::post('/login', 'Common\AuthController@postLogin')->name('login.post');
Route::get('/register/{guard}', 'Common\RegistrationController@getRegister')->name('register.get');
Route::post('/register/{guard}', 'Common\RegistrationController@postRegister')->name('register.post');
Route::get("/register/success/{guard}", "Common\RegistrationController@getSuccess")->name("register.success.get");
});
Route::group(["prefix" => "admin/auth"], function() {
Route::get("/login", "Admin\AuthController@getLogin")->name("admin.auth.login.get");
Route::post("/login", "Admin\AuthController@postLogin")->name("admin.auth.login.post");
Route::get("/logout", "Admin\AuthController@getLogout")->name("admin.auth.logout.get");
});
routes/admin.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "admin" middleware group. Routes are prefixed with "/admin"
| Now create something great!
|
*/
Route::get("/", "DashboardController@getIndex")->name("admin.dashboard");
// rest omitted
Http/Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* 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,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::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\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
'admin' => [
'web',
'auth:admin',
'nav:admin', // nav is custom middleware for loading navigation config to nwidart/laravel-menus library
],
'organization' => [
'web',
'auth:organization',
'nav:organization',
],
'volunteer' => [
'web',
'auth:volunteer',
'nav:volunteer',
],
];
/**
* 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' => \App\Http\Middleware\AuthMiddleware::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'nav' => \App\Http\Middleware\NavigationBuilder::class,
];
}
AuthMiddlware.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class AuthMiddleware {
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard) {
if (!Auth::guard($guard)->check()) {
return redirect()->route(config("auth.guards.$guard.redirect"));
}
return $next($request);
}
}
为了结束这个,我想说欢迎任何建议或评论。我需要确定这是否是我的本地问题,或者这是否与 Laravel 有关,以便我可以在他们的 GitHub 页面上打开一个问题。
经过进一步调查,我发现问题是由barryvdh/laravel-debugbar包引起的。通过删除它或将应用程序变成 production/debug=false,一切都按预期工作。一旦收到 barryvdh 的回复,我将更新此答案。