在我们的laravel 5应用程序中,登录是通过ajax进行的。如果用户在会话到期之前注销并重新登录,则一切正常。但是,如果用户注销并在该页面上保持空闲直到会话过期,则如果用户尝试重新登录,则会得到csrfTokenMismatch
异常。
我知道在verifyCsrfToken
中间件中,laravel会检查会话是否与csrf令牌匹配。同样在Guard.php logout()
方法中,会话将在注销时被清除。
所以我的问题是:
注销时会话真的被刷新了吗?如果是的话,为什么用户仍然可以在我设置的会话到期之前重新登录?
会话过期时csrf令牌会发生什么?
最后,这个问题通常是如何以优雅的方式处理的?
提前感谢!
这个答案参考了5.4版本,可能是以前的版本,但我还没有测试过。
问题的根源是客户端的CSRF令牌已过期,这会导致使用该令牌对服务器进行POST失败。
如果你使用AJAX,你可以使用API路由,默认情况下不做CSRF验证。
您可以关闭特定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''Exception$Exception*@return ''Illuminate''Http''Response*/公共函数呈现($request,Exception$Exception({if($exception instanceof''Illuminate''Session''TokenMismatchException({//令牌不匹配是一个安全问题,请确保注销。Auth::logout((;//告诉用户发生了什么。session((->flash('警告','您的会话已过期。请登录以继续。'(;//转到登录。return redirect((->route('登录'(;}return parent::render($request,$exception(;}
顺便说一句,要测试这两项更改,您可以修改会话设置。我只是将生存期设置为1
进行测试。然后,在完成时将其设置为后退(默认情况下为120(。您需要登录,加载表单页面,等待一分钟以上,然后尝试POST。
config/session.php/*|--------------------------------------------------------------------------|会话生存期|--------------------------------------------------------------------------||您可以在此处指定您希望会话的分钟数|以允许在其到期之前保持空闲。如果你想要它们|要在浏览器关闭时立即过期,请设置该选项。|*/"寿命"=>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);
}
}