会话超时后 laravel csrf 令牌不匹配异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31210618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
laravel csrf token mismatch exception after session timeout
提问by shangsunset
in our laravel 5 app, the login is through ajax. if user logout and log back in before session expires, everything is fine. but if user logout and stay idle on that page until session is expired, user will get a csrfTokenMismatch
exception if they attempt to log back in.
在我们的 Laravel 5 应用程序中,登录是通过 ajax 进行的。如果用户注销并在会话到期前重新登录,则一切正常。但是如果用户注销并在该页面上保持空闲直到会话过期,则用户csrfTokenMismatch
在尝试重新登录时将收到异常。
i know in verifyCsrfToken
middleware, laravel checks if session matches with the csrf token. also in Guard.php logout()
method, session will be cleared on logout.
我知道在verifyCsrfToken
中间件中,laravel 检查会话是否与 csrf 令牌匹配。同样在Guard.php logout()
方法中,会话将在注销时被清除。
so my questions are:
所以我的问题是:
is session really flushed on logout, if so how come user can still log back in before the session i set expires?
会话是否真的在注销时刷新,如果是这样,用户为什么仍然可以在我设置的会话到期之前重新登录?
what happens to csrf token when session is expired?
会话过期时 csrf 令牌会发生什么?
and lastly, how is this issue usually handled in an elegant way?
最后,这个问题通常如何以优雅的方式处理?
Thanks in advance!
提前致谢!
回答by JR Lawhorne
This answer is in reference to version 5.4, perhaps previous versions but I haven't tested those.
这个答案参考了 5.4 版,也许是以前的版本,但我还没有测试过。
The root of the problem is the CSRF token is expired on the client side which makes any POST to the server fail with that token.
问题的根源在于客户端的 CSRF 令牌已过期,这使得使用该令牌对服务器的任何 POST 失败。
IF you're using AJAX, you could use the API routes which do not do CSRF verification by default.
如果您使用 AJAX,您可以使用默认情况下不进行 CSRF 验证的 API 路由。
You couldturn off CSRF verification for specific URIs. In this case, I'm turning off CSRF verification for /logout
. This approach works well if you trulywant to exclude certain URIs from verification.
您可以关闭特定 URI 的 CSRF 验证。在这种情况下,我将关闭/logout
. 如果您真的想从验证中排除某些 URI,则此方法非常有效。
app/Http/Middleware/VerifyCsrfToken.php /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ '/logout' ];
In addition, you should handle the CSRF error when it occurs in a way that works well for your application. Below is an example of something very basic you could do.
此外,当 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); }
By the way, to test both of these changes, you can modify the session settings. I just set the lifetime to 1
for testing. Then, set it back when you're finished (it is 120 by default). You'll want to login, load your form page, wait over a minute, then attempt your POST.
顺便说一下,要测试这两个更改,您可以修改会话设置。我只是将生命周期设置为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,
回答by shock_gone_wild
There is a cookie with name XSRF-Token, that has a default live-time of 2 hours...
有一个名为 XSRF-Token 的 cookie,它的默认实时时间为 2 小时...
I handled TokenMissmatchExceptions on login forms like this by modifying App/Exceptions/Handler.php :
我通过修改 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);
}
回答by Neo
In your case I think you would truly benefit in using this:
在你的情况下,我认为你会真正受益于使用这个:
https://github.com/GeneaLabs/laravel-caffeine
https://github.com/GeneaLabs/laravel-caffeine
I personaly handle non-ajax situations like this, you could tweak it for Ajax requests to return some useful json for error handling:
我个人处理这样的非 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);
}
}