在我们的laravel 5应用程序中,登录是通过ajax。如果用户注销并在会话到期之前重新登录,一切都很好。但如果用户注销并在该页面上保持空闲状态直到会话过期,则用户在尝试重新登录时将获得csrfTokenMismatch
异常。
我知道在verifyCsrfToken
中间件中,laravel检查会话是否与csrf令牌匹配。同样在Guard.php logout()
方法中,会话将在注销时清除。
所以我的问题是:
是会话在注销时真的刷新了,如果是这样,用户如何在我设置的会话到期之前重新登录?
会话过期时csrf令牌会发生什么?
最后,这个问题通常如何以优雅的方式处理?
提前致谢!
答案 0 :(得分:3)
这个答案是参考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,
答案 1 :(得分: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);
}
答案 2 :(得分:0)
在你的情况下,我认为你真的会受益于这个:
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);
}
}