Laravel 会话超时,额外的注销代码

Posted

技术标签:

【中文标题】Laravel 会话超时,额外的注销代码【英文标题】:Laravel session timeout, extra logout code 【发布时间】:2020-03-20 17:10:47 【问题描述】:

底线:

如何在会话超时时注销用户?


详细问题:

我有一个 Laravel 5.6.* 应用程序,该项目要求用户在用户空闲时注销。我已经尝试过这里给出的解决方案,但没有一个对我有用。

然后我偶然发现了这篇文章: https://laravel-tricks.com/tricks/session-timeout-for-logged-in-user 并没有成功。


我想要什么:

在会话超时时自动注销用户。在注销之前,将Users 表上的is_logged_in 属性设置为false0。我如何做到这一点?


到目前为止我尝试过的代码:

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中间件

<?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,
     ],
];

【问题讨论】:

会话超时后屏幕上是否显示任何错误? 不。没有错误,它只是注销但不对数据库执行任何数据库操作。 在注销前执行数据库操作或尝试使用像 \Auth::guard('admin')->logout();return redirect()->route('admin.login'); 不。还是一样。 您是否获得了更新的用户详细信息 dd($user);更新后?is_logged_in=false in db? 【参考方案1】:

您正在比较与中间件中相同的会话生命周期。

这意味着当会话到期时,您的中间件将不会(永远)被调用。用户将移动到登录页面。

如果您想在数据库中保存条目,您可以设置长时间会话生存期,并在中间件中使用您自定义的时间来注销。

config/session.php 中的变化

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

中间件更改如下,两小时后退出。

   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'));
       

   

通过这种方式,您的会话不会自动过期,您可以操作数据。

【讨论】:

您的解决方案有效,但前提是session('lastActivityTime') 有价值。当会话过期时,session('lastActivity') 会被 Laravel 自动更新并重定向到登录页面。在此之前,我想将is_logged_in 属性设置为false0,我该如何实现? 这就是我想说的。如果会话自动过期,我们无法获取数据,因此解决方案是增加会话生命周期,在中间件中,使用自定义时间注销。检查更新的答案。【参考方案2】:

注销前需要更新数据库。因为注销后无法执行$user-&gt;update()。所以请尝试以下方式:

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'));

【讨论】:

不。它没有用。仅在应用您的解决方案后,is_logged_in 列才设置为 1 @SaiyanPrince 这意味着数据库已更新。现在的问题是你想在is_logged_in 列中保存什么?是true or false 还是0 or 1 不。 1true 在用户登录时设置。我想在用户通过会话超时注销时将其设置为false0。我已经完成了手动过程。我现在正在寻找数据库表的自动更新。【参考方案3】:

请在中间件中检查小于120,例如如果条件低于115或119,然后检查它

if (now()->diffInMinutes(session('lastActivityTime')) == config('session.lifetime')) 
....

【讨论】:

以上是关于Laravel 会话超时,额外的注销代码的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 身份验证会话超时

Laravel TokenMismatchException 会话超时

Laravel 会话过期事件

Laravel 会话表添加附加列

如何在会话超时或结束时注销用户

Laravel 5.2:在用户登录/注销和注册后显示会话闪烁消息