首页 文章

会话超时后laravel csrf令牌不匹配异常

提问于
浏览
5

在我们的laravel 5应用程序中,登录是通过ajax . 如果用户注销并在会话到期之前重新登录,一切都很好 . 但是如果用户注销并在该页面上保持空闲直到会话过期,则用户在尝试重新登录时将获得 csrfTokenMismatch 异常 .

我知道在 verifyCsrfToken 中间件中,laravel检查会话是否与csrf令牌匹配 . 同样在 Guard.php logout() 方法中,会话将在注销时清除 .

所以我的问题是:

会话是否真的在注销时刷新,如果是这样,为什么用户仍然可以在我设置的会话到期之前重新登录?

会话过期时csrf令牌会发生什么?

最后,这个问题通常如何以优雅的方式处理?

提前致谢!

3 回答

  • 1

    有一个名为XSRF-Token的cookie,其默认实时时间为2小时......

    我通过修改App / Exceptions / Handler.php来处理这样的登录表单上的TokenMissmatchExceptions:

    // ....
    use Illuminate\Session\TokenMismatchException;
    // ....
    
    
    public function render($request, Exception $e)
    {
        if($e instanceof TokenMismatchException) {
            $uri = \Route::current()->uri();
            if($uri == "login") {
                return redirect()->route('your.login.route')
                                 ->withErrors("Login Form was open too long. 
                                               Please try to login again");
            }
        }
        return parent::render($request, $e);
    }
    
  • 1

    这个答案是参考5.4版本,也许是以前的版本,但我还没有测试过 .

    问题的根源是客户端的CSRF令牌已过期,这使得对服务器的任何POST都会失败 .

    如果您使用的是AJAX,则可以使用默认情况下不进行CSRF验证的API路由 .

    您可以关闭特定URI的CSRF验证 . 在这种情况下,我正在关闭 /logout 的CSRF验证 . 如果您确实要从验证中排除某些URI,则此方法很有效 .

    app/Http/Middleware/VerifyCsrfToken.php
    
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
       '/logout'
    ];
    

    此外,您应该以适合您的应用程序的方式处理CSRF错误 . 以下是您可以做的非常基本的示例 .

    app/Exceptions/Handler.php
    
    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $exception)
    {
        if($exception instanceof \Illuminate\Session\TokenMismatchException){
            // token mismatch is a security concern, ensure logout.
            Auth::logout();
    
            // Tell the user what happened.
            session()->flash('alert-warning','Your session expired. Please login to continue.');
    
            // Go to login.
            return redirect()->route('login');
         }
    
        return parent::render($request, $exception);
    }
    

    顺便说一下,要测试这两个更改,您可以修改会话设置 . 我只是将生命周期设置为 1 进行测试 . 然后,当您想要登录,加载表单页面,等待一分钟,然后尝试POST时,将其设置回来 .

    config/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' => 1,
    
  • 0

    在您的情况下,我认为您将真正受益于使用此:

    https://github.com/GeneaLabs/laravel-caffeine

    我个人处理像这样的非ajax情况,你可以调整它为Ajax请求返回一些有用的json进行错误处理:

    public function render($request, Exception $e)
        {
             if ($e instanceof \Illuminate\Session\TokenMismatchException) {
    
                  return redirect()
                      ->back()
                      ->withInput($request->except('_token'))
                      ->withMessage('Your explanation message depending on how much you want to dumb it down, lol! ');
    
            }
    
            return parent::render($request, $e);
        }
    }
    

相关问题