6

Bottom line:

How to logout the user on session time out?


Detailed Question:

I have a Laravel 5.6.* application and the project demands the user to logout whenever the user is idle. I have tried the solutions that are given here, but none of them worked for me.

Then I stumbled upon this post: https://laravel-tricks.com/tricks/session-timeout-for-logged-in-user and made my way through it to no success.


What I want:

Logout the user automatically on session timeout. Before logging out, set is_logged_in attribute to false or 0 on the Users table. How do I achieve this?


Code that I have tried so far:

session.php

/*
 |--------------------------------------------------------------------------
 | Session Lifetime
 |--------------------------------------------------------------------------
 |
 | Here you may specify the number of minutes that you wish the session
 | to be allowed to remain idle before it expires. If you want them
 | to immediately expire on the browser closing, set that option.
 |
 */

 'lifetime' => env('SESSION_LIFETIME', 120),

 'expire_on_close' => false,

SessionTimeOut.php Middleware

<?php

namespace App\Http\Middleware;

use Closure;
use App\Traits\CacheQueryResults;

class SessionTimeOut
{
    use CacheQueryResults;

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // session()->forget('lastActivityTime');

        if (! session()->has('lastActivityTime')) {
            session(['lastActivityTime' => now()]);
        }

        // dd(
        //     session('lastActivityTime')->format('Y-M-jS h:i:s A'),
        //     now()->diffInMinutes(session('lastActivityTime')),
        //     now()->diffInMinutes(session('lastActivityTime')) >= config('session.lifetime')
        // );

        if (now()->diffInMinutes(session('lastActivityTime')) >= (config('session.lifetime') - 1) ) {
            if (auth()->check() && auth()->id() > 1) {
               $user = auth()->user();
               auth()->logout();

               $user->update(['is_logged_in' => false]);
               $this->reCacheAllUsersData();

               session()->forget('lastActivityTime');

               return redirect(route('users.login'));
           }

       }

       session(['lastActivityTime' => now()]);

       return $next($request);
    }
}

Kernel.php

/**
 * 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,
         \App\Http\Middleware\SessionTimeOut::class,
     ],
];
Saiyan Prince
  • 3,930
  • 4
  • 28
  • 71

3 Answers3

7

You are comparing session lifetime same as in middleware.

That Means when session will expire, your middleware will not(never) called.And user will move to login page.

If you want to save entry in Database, You can set long-time session lifetime, and in middleware use your custom time to logout.

Change in config/session.php

'lifetime' => 525600, // for one year, it will be in minute, use as you want. 

Change in middleware as below, log out after two hours.

   if (now()->diffInMinutes(session('lastActivityTime')) >= (120) ) {  // also you can this value in your config file and use here
       if (auth()->check() && auth()->id() > 1) {
           $user = auth()->user();
           auth()->logout();

           $user->update(['is_logged_in' => false]);
           $this->reCacheAllUsersData();

           session()->forget('lastActivityTime');

           return redirect(route('users.login'));
       }

   }

By this way your session will not expire automatically and you can manipulate data.

Yasin Patel
  • 5,624
  • 8
  • 31
  • 53
  • Your solution works, but only when `session('lastActivityTime')` has value in it. When the session is expired, the `session('lastActivity')` is renewed automatically by Laravel and redirects to the login page. Just before that, I want to set `is_logged_in` attribute to `false` or `0`, How do I achieve that? – Saiyan Prince Nov 26 '19 at 08:07
  • 1
    Thats i want to say. If session automatically get expire, we cannot fetch data, so solution is increase your session lifetime and in middleware, use you custom time to logout. Check updated answer. – Yasin Patel Nov 26 '19 at 09:11
0

Need to update the database before logout. Because after logout can't perform $user->update(). so that try following way:

if (auth()->check() && auth()->id() > 1) {
    $user = auth()->user();        

    $user->update(['is_logged_in' => false]);
    $this->reCacheAllUsersData();

    session()->forget('lastActivityTime');

    //Add Logout method here..
    auth()->logout();

    return redirect(route('users.login'));
}
Amit Senjaliya
  • 2,867
  • 1
  • 10
  • 24
  • Nope. It didn't work. The `is_logged_in` column is set to `1` only after applying your solution. – Saiyan Prince Nov 25 '19 at 12:22
  • @SaiyanPrince That means database updated. Now the question is what do you want to save in the `is_logged_in` column? is it `true or false` OR `0 or 1`. – Amit Senjaliya Nov 25 '19 at 12:25
  • Nope. `1` i.e., `true` is set when the user logs in. I want to set it to `false` or `0` when the user is logged out via session timeout. I already have the manual process done. I am now looking for automatic updating of the database table. – Saiyan Prince Nov 25 '19 at 12:28
0

please check less than 120 in middleware,ex 115 or 119 in below if condition and then check it

if (now()->diffInMinutes(session('lastActivityTime')) == config('session.lifetime')) {
....
}
Arshad Shaikh
  • 564
  • 1
  • 3
  • 13