【问题标题】:laravel csrf token mismatch exception after session timeout会话超时后的 laravel csrf 令牌不匹配异常
【发布时间】:2015-09-21 12:29:20
【问题描述】:

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

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

所以我的问题是:

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

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

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

提前致谢!

【问题讨论】:

    标签: php ajax session laravel


    【解决方案1】:

    这个答案是参考 5.4 版本,可能是以前的版本,但我没有测试过。

    问题的根源在于客户端的 CSRF 令牌已过期,这使得到服务器的任何 POST 都因该令牌而失败。

    如果你使用 AJAX,你可以使用默认不做 CSRF 验证的 API 路由。

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

    app/Http/Middleware/VerifyCsrfToken.php
    
    /**
     * 应该从 CSRF 验证中排除的 URI。
     *
     * @var 数组
     */
    受保护的 $except = [
       '/登出'
    ];
    

    此外,您应该以适合您的应用程序的方式处理 CSRF 错误。下面是一个你可以做的非常基本的事情的例子。

    app/Exceptions/Handler.php
    
    /**
     * 将异常渲染到 HTTP 响应中。
     *
     * @param \Illuminate\Http\Request $request
     * @param \异常 $异常
     * @return \Illuminate\Http\Response
     */
    公共函数渲染($请求,异常$异常)
    {
        if($exception instanceof \Illuminate\Session\TokenMismatchException){
            // 令牌不匹配是一个安全问题,请确保注销。
            验证::注销();
    
            // 告诉用户发生了什么。
            session()->flash('alert-warning','您的会话已过期。请登录以继续。');
    
            // 去登录。
            返回重定向()->路由('登录');
         }
    
        返回父级::render($request, $exception);
    }
    

    顺便说一句,要测试这两个更改,您可以修改会话设置。我只是将生命周期设置为1 进行测试。然后,完成后将其重新设置(默认为 120)。您需要登录,加载表单页面,等待一分钟,然后尝试 POST。

    配置/session.php
    
        /*
        |------------------------------------------------- -------------------------
        |会话生命周期
        |------------------------------------------------- -------------------------
        |
        |在这里您可以指定您希望会话的分钟数
        |允许在到期前保持空闲状态。如果你想要他们
        |要在浏览器关闭时立即过期,请设置该选项。
        |
        */
    
        '终生' => 1,
    
    

    【讨论】:

      【解决方案2】:

      有一个名为 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);
      }
      

      【讨论】:

        【解决方案3】:

        在你的情况下,我认为你会真正受益于使用这个:

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

        【讨论】:

          猜你喜欢
          • 2019-02-27
          • 2017-10-28
          • 1970-01-01
          • 2016-12-06
          • 2014-11-21
          • 2020-07-08
          • 2016-12-10
          • 2016-09-20
          相关资源
          最近更新 更多