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

sha*_*set 7 php ajax session laravel

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

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

所以我的问题是:

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

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

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

提前致谢!

JR *_*rne 5

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

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

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

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

app / Http / Middleware / VerifyCsrfToken.php

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

此外,当CSRF错误发生时,应以适合您的应用程序的方式对其进行处理。下面是一个您可以做的非常基本的事情的例子。

app / Exceptions / Handler.php

/ **
 *将异常呈现到HTTP响应中。
 *
 * @param \ Illuminate \ Http \ Request $ request
 * @param \ Exception $ exception
 * @return \ Illuminate \ Http \ Response
 * /
公共函数render($ request,Exception $ exception)
{
    if($ Illuminate \ Session \ TokenMismatchException的$ exception实例){
        //令牌不匹配是安全问题,请确保注销。
        Auth :: logout();

        //告诉用户发生了什么。
        session()-> flash('alert-warning','您的会话已过期。请登录以继续。');

        //登录。
        返回redirect()-> route('login');
     }

    返回parent :: render($ request,$ exception);
}

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

config / session.php

    / *
    | ------------------------------------------------- -------------------------
    | 会话寿命
    | ------------------------------------------------- -------------------------
    |
    | 您可以在此处指定您希望会议进行的分钟数
    | 被允许在其过期之前保持空闲状态。如果你想要他们
    | 要立即在浏览器关闭时到期,请设置该选项。
    |
    * /

    '寿命'=> 1,


sho*_*ild 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);
}
Run Code Online (Sandbox Code Playgroud)