【问题标题】:Laravel 5.6 - Session is not persisting after it expiresLaravel 5.6 - 会话过期后不会持续存在
【发布时间】:2019-01-05 14:58:50
【问题描述】:

我的两个本地环境有一个非常奇怪的问题。一旦我的会话由于太久没有刷新而过期,将按预期创建一个新会话。但是,如果我在公共站点上浏览(不受 Auth 保护),会话将不会持续存在,并且对于每个 get/post 请求,它将被忽略并创建一个新的(我可以在 XRSF 令牌上看到以及正在存储/框架中创建的新文件)。

这里有几个场景:

  1. 如果没有用户登录,一切正常。

  2. 如果管理员用户已登录(选中“记住我”),但公共用户未登录,则访问任何公共(未受保护)路由(使用默认 web 中间件)将如上所述重新创建会话.但是,一旦我访问admin middlware 下的任何路由(web middleware + auth check),会话将保持不变,之后,公共路由的问题就消失了。

  3. 如果两个用户都登录并且我访问任何受保护的路由,会话将立即停止。

我尝试了以下方法,但没有成功:

  • 阅读并尝试其他线程的建议
  • 删除所有缓存
  • 重新安装 XAMPP
  • 尝试了不同的浏览器(Chrome、Edge 和新安装的 Firefox 的结果相同)
  • 设置 SESSION_DOMAIN - 这实际上破坏了 Edge,会话完全停止工作
  • 已删除网站 cookie
  • 已更改 APP_URL 和 APP_NAME
  • 已尝试用于会话的文件和数据库驱动程序
  • 通过 VHost(例如 http://mySite/)和 php artisan 服务器使用 XAMPP 访问站点
  • 确保web 中间件不会两次应用于任何路由

解决问题的方法:

  • 访问受保护的页面
  • 删除 cookie
  • 重新打开浏览器

我重现问题的环境:

  1. 我的电脑

    • Windows 10 Pro x64,内部版本 1709
    • PHP 7.2.0 (XAMPP)
  2. 我的笔记本电脑

    • Windows 10 Pro x64,内部版本 1803
    • PHP 7.2.7 (XAMPP)
  3. 同事的笔记本电脑

    • 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


【解决方案1】:

经过更多调查,我发现问题是由 barryvdh/laravel-debugbar 包引起的。通过删除它或将应用程序转换为生产/调试 = 假,一切都按预期工作。收到 barryvdh 的回复后,我将更新此答案。

【讨论】:

    猜你喜欢
    • 2017-02-16
    • 1970-01-01
    • 2018-06-25
    • 2015-08-26
    • 2019-01-29
    • 2016-01-20
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多