samedi 28 juillet 2018

Laravel 5.6 - Session is not persisting after it expires

I have a very weird issue with my two of my local environments. Once my session expires due to not being refreshed for too long, a new session will be created as expected. However, if I am browsing on public site (which is not under Auth protection), the session will not persist and with each get/post request, it will be ignored and a new one will be created (I can see that on XRSF token and new file being created in storage/framework).

Here are few scenarios:

  1. If no user is logged in, everything works fine.

  2. If admin user is logged in, but public user is not, accessing any public (unprotected) route (which uses default "web" middleware) will recreate session as described above. However, once I access any route under "admin" middlware ("web" middleware + auth check), session will stick and after that, the issue for public route disappears.

  3. If both users are logged in and I access any protected route, session sticks immediately.

I tried the following, without any success:

  • reading and trying out suggestions from other threads
  • remove all caches
  • reinstalled XAMPP
  • tried different browsers (same result for Chrome, Edge and freshly installed Firefox)
  • setting SESSION_DOMAIN - this actually broke Edge, sessions stopped working altogether
  • removed site cookies
  • changed APP_URL and APP_NAME
  • tried file and database drivers for session
  • accessed site using XAMPP through VHost (e.g. http://mySite/) and through php artisan server

What resolves the issue:

  • accessing protected page
  • deleting cookies
  • reopening browser

Environments where I reproduced the issue:

  1. My PC

    • Windows 10 Pro x64, build 1709
    • PHP 7.2.0
  2. My laptop

    • Windows 10 Pro x64, build 1803
    • PHP 7.2.7

The issue was not reproduced on colleague's macOS running MAMP with PHP 7.2.

What probably does not cause the issue:

  • file permissions
  • my Laravel configuration (as I tried dozen of suggestions in similar threads)
  • XAMPP installation

What might caused the issue:

  • cookies (although I have no idea how)
  • PHP settings
  • Laravel (given the weird behavior in given scenarios, I cannot exclude this option yet)
  • Windows

Here are some files that might be useful for you:

.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);
    }
}


To end this, I would like to say that any suggestion or comment is welcomed. I need to determine if this is my local issue, or if this has something to do with Laravel so that I can open an issue on their GitHub page.



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire