【发布时间】:2019-01-05 14:58:50
【问题描述】:
我的两个本地环境有一个非常奇怪的问题。一旦我的会话由于太久没有刷新而过期,将按预期创建一个新会话。但是,如果我在公共站点上浏览(不受 Auth 保护),会话将不会持续存在,并且对于每个 get/post 请求,它将被忽略并创建一个新的(我可以在 XRSF 令牌上看到以及正在存储/框架中创建的新文件)。
这里有几个场景:
如果没有用户登录,一切正常。
如果管理员用户已登录(选中“记住我”),但公共用户未登录,则访问任何公共(未受保护)路由(使用默认
web中间件)将如上所述重新创建会话.但是,一旦我访问adminmiddlware 下的任何路由(webmiddleware + auth check),会话将保持不变,之后,公共路由的问题就消失了。如果两个用户都登录并且我访问任何受保护的路由,会话将立即停止。
我尝试了以下方法,但没有成功:
- 阅读并尝试其他线程的建议
- 删除所有缓存
- 重新安装 XAMPP
- 尝试了不同的浏览器(Chrome、Edge 和新安装的 Firefox 的结果相同)
- 设置 SESSION_DOMAIN - 这实际上破坏了 Edge,会话完全停止工作
- 已删除网站 cookie
- 已更改 APP_URL 和 APP_NAME
- 已尝试用于会话的文件和数据库驱动程序
- 通过 VHost(例如 http://mySite/)和 php artisan 服务器使用 XAMPP 访问站点
- 确保
web中间件不会两次应用于任何路由
解决问题的方法:
- 访问受保护的页面
- 删除 cookie
- 重新打开浏览器
我重现问题的环境:
-
我的电脑
- Windows 10 Pro x64,内部版本 1709
- PHP 7.2.0 (XAMPP)
-
我的笔记本电脑
- Windows 10 Pro x64,内部版本 1803
- PHP 7.2.7 (XAMPP)
-
同事的笔记本电脑
- macOS High Sierra 10.13.6
- PHP 7.2.1 (MAMP)
什么可能不会导致问题:
- 文件权限
- 我的 Laravel 配置(我在类似的线程中尝试了十几个建议)
- XAMPP 或 MAMP
- 操作系统
可能导致问题的原因:
- 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");
});
路由/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 页面上打开一个问题。
【问题讨论】:
-
Laravel Session 服务不依赖原生 PHP 会话。
-
检查您是否没有意外两次将 Web 中间件应用于路由,这几乎肯定会导致会话问题。检查
RouteServiceProvider.php并检查您的路线,以确保您只应用了网络中间件 1 次。 -
@BenjaminDowson 我已经运行了
php artisan route:list并确保我的所有路由只有一个中间件或只有一个中间件组。很少有受保护的路由会两次使用 Web 中间件,但修复它并没有什么区别。我在许多有关会话的线程中都看到了这一点,可惜它没有用。 -
更新原始问题,因为我们也在 macOS 上复制了这个问题。
-
我向 Laravel 报告了问题 - github.com/laravel/framework/issues/25081
标签: laravel session laravel-5 xampp laravel-5.6