[英]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.