会话超时后的 laravel csrf 令牌不匹配异常
Posted
技术标签:
【中文标题】会话超时后的 laravel csrf 令牌不匹配异常【英文标题】:laravel csrf token mismatch exception after session timeout 【发布时间】:2015-09-21 12:29:20 【问题描述】:在我们的 laravel 5 应用程序中,登录是通过 ajax 进行的。如果用户在会话到期之前注销并重新登录,一切都很好。但是如果用户注销并在该页面上保持空闲直到会话过期,如果用户尝试重新登录,则会收到csrfTokenMismatch
异常。
我知道在verifyCsrfToken
中间件中,laravel 检查会话是否与 csrf 令牌匹配。同样在Guard.php logout()
方法中,会话将在注销时被清除。
所以我的问题是:
会话是否真的在注销时刷新,如果是这样,为什么用户仍然可以在我设置的会话过期之前重新登录?
会话过期时 csrf 令牌会发生什么?
最后,这个问题通常如何以优雅的方式处理?
提前致谢!
【问题讨论】:
【参考方案1】:这个答案是参考 5.4 版本,可能是以前的版本,但我没有测试过。
问题的根源在于客户端的 CSRF 令牌已过期,这使得到服务器的任何 POST 都因该令牌而失败。
如果你使用 AJAX,你可以使用默认不做 CSRF 验证的 API 路由。
您可以关闭特定 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 \异常 $异常 * @return \Illuminate\Http\Response */ 公共函数渲染($请求,异常$异常) if($exception instanceof \Illuminate\Session\TokenMismatchException) // 令牌不匹配是一个安全问题,请确保注销。 验证::注销(); // 告诉用户发生了什么。 session()->flash('alert-warning','您的会话已过期。请登录以继续。'); // 去登录。 返回重定向()->路由('登录'); 返回父级::render($request, $exception);
顺便说一句,要测试这两个更改,您可以修改会话设置。我只是将生命周期设置为1
进行测试。然后,完成后将其重新设置(默认为 120)。您需要登录,加载表单页面,等待一分钟,然后尝试 POST。
配置/session.php /* |------------------------------------------------- ------------------------- |会话生命周期 |------------------------------------------------- ------------------------- | |在这里您可以指定您希望会话的分钟数 |允许在到期前保持空闲状态。如果你想要他们 |要在浏览器关闭时立即过期,请设置该选项。 | */ '终生' => 1,
【讨论】:
【参考方案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);
【讨论】:
【参考方案3】:在你的情况下,我认为你会真正受益于使用这个:
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);
【讨论】:
以上是关于会话超时后的 laravel csrf 令牌不匹配异常的主要内容,如果未能解决你的问题,请参考以下文章
Laravel + Vue.js (axios) - CSRF 令牌不匹配
为啥我在 laravel 中运行测试时收到“CSRF 令牌不匹配”?