繁体   English   中英

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

[英]laravel csrf token mismatch exception after session timeout

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

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

所以我的问题是:

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

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

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

提前致谢!

这个答案参考了 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以进行测试。 然后,完成后将其设置回原位(默认为 120)。 您需要登录,加载表单页面,等待一分钟,然后尝试 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,

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM