解决 laravel 中令牌不匹配错误的正确方法是什么?
What is the right way to resolve token mismatch error in laravel?
自从我将 laravel 更新到 5.4 后,我不断得到:
TokenMismatchException in VerifyCsrfToken.php line 68
抛出异常。在挖掘和阅读大量帖子和 github 问题之后,我发现我的令牌不匹配 :)。关键是我的 laravel 应用程序设置了令牌 "XSRF-TOKEN" 的加密版本而不是它的普通 (X-CSRF-TOKEN) 副本,并且助手 csrf_token()
吐出普通令牌因此不匹配令牌。令人困惑的是,为什么当我得到 XSRF-TOKEN(缺少 X-)时文档会提到 X-XSRF-TOKEN?所以问题是:
- 缺少的 "X-" 有什么意义吗?
- 如何将令牌的加密版本更改为普通版本? (不管问题 #3)
- 我是应该尝试从加密令牌中制作一个普通令牌,还是加密
csrf_token()
更好? (这有关系吗,因为连接是加密的?)
- 在
\MiddleWare\EncryptCookies.php
中的 $excepted
下列出 "XSRF-TOKEN" 是一个可行的选择,还是您可以建议更好的解决方案? (这让我们回到了问题 #3)
很抱歉提出这么多问题,在此先感谢您!
编辑
我的问题重读了好几遍后,我得出的结论是,它们不够清楚,与标题不符。我的问题是令牌不匹配,我认为清除我的疑虑会引导我找到解决方案,我感谢@ThomasMoors 的耐心和帮助。我会接受他的回答,虽然我用不同的方式解决了我的问题,但正是他的帮助让我找到了解决方案!我还发布了我自己的答案,描述了我如何解决我的问题以帮助其他有类似问题的人!
The function that checks the token tries to find it (1) inside a request plain with the key _token
, if it does not find it, it will try to look inside (2) the request headers with the key X-CSRF-TOKEN
. The token to match is stored inside the session, where the session lives depends on your config.
/**
* Determine if the session and input CSRF tokens match.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function tokensMatch($request)
{
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
if ( ! $token && $header = $request->header('X-XSRF-TOKEN'))
{
$token = $this->encrypter->decrypt($header);
}
return StringUtils::equals($request->session()->token(), $token);
}
Q: 缺失的"X-"有什么意义吗?
A: Laravel stores the current CSRF token in a XSRF-TOKEN cookie that is
included with each response generated by the framework. You can use
the cookie value to set the X-XSRF-TOKEN request header.
This cookie is primarily sent as a convenience since some JavaScript
frameworks and libraries, like Angular and Axios, automatically place
its value in the X-XSRF-TOKEN header.
Q: 如何将令牌的加密版本更改为普通版本? (不管问题 #3)
A:如上面的代码(来自 github)\Illuminate\Contracts\Encryption\Encrypter
有一个名为 decrypt()
的函数可以执行此操作
Q: 我是应该尝试用加密的令牌制作一个普通令牌还是加密 csrf_token() 更好? (这有关系吗,因为连接是加密的?)
A: 没关系,因为令牌里面没有数据,它只是来自您站点的合法请求的标识符,而不是某些 ajax/xhr 从另一个域调用。阅读更多关于 https://en.wikipedia.org/wiki/Cross-site_request_forgery
Q:是否在 \MiddleWare\EncryptCookies.php 中的 $excepted 下列出 "XSRF-TOKEN" 一个可行的选项或者可能你建议一个更好的解决方案吗? (这让我们回到了问题 #3)
A: 令牌没有理由在任何时候都在 cookie 中,对吗?
更新
看来从5.0到5.4确实是上面函数中的东西has changed。现在看起来像这样:
protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);
return is_string($request->session()->token()) &&
is_string($token) &&
hash_equals($request->session()->token(), $token);
}
虽然我无法确定问题的根源(由于缺乏使用框架的经验),但我终于可以解决我的问题。到目前为止我错过的是一些 中间件 类 被移动到 app/Http/Kernel.[=23= 中的不同中间件组] 文件(我的问题可能是因为 它们的加载顺序 发生了变化,或者可能是因为其中一些根本没有加载?)。我很确定,这是我的问题的原因,因为我不断地重新加载我的页面并清除缓存,就像 github 上建议的那样,这是 jeremykenedy 的建议。建议调用以下命令:
sudo rm -rf storage/framework/sessions/*
sudo php artisan cache:clear
sudo php artisan clear-compiled
sudo composer dump-autoload
你们所有处理类似问题的人可能已经遇到过数百次了。我经常发现的另一个建议是更改存储文件夹的权限,这可能有助于你们中的一些人解决类似的问题!
我发现了一个关于令牌不匹配异常的有趣的事情。我在 AppServiceProvider 中将约会时间伪造为:
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Carbon::setTestNow('2000-07-05 4:00 pm');
}
之后我无法登录我的 laravel 应用程序。否则只需一个命令就足以解决令牌不匹配异常。
php artisan config:clear
自从我将 laravel 更新到 5.4 后,我不断得到:
TokenMismatchException in VerifyCsrfToken.php line 68
抛出异常。在挖掘和阅读大量帖子和 github 问题之后,我发现我的令牌不匹配 :)。关键是我的 laravel 应用程序设置了令牌 "XSRF-TOKEN" 的加密版本而不是它的普通 (X-CSRF-TOKEN) 副本,并且助手 csrf_token()
吐出普通令牌因此不匹配令牌。令人困惑的是,为什么当我得到 XSRF-TOKEN(缺少 X-)时文档会提到 X-XSRF-TOKEN?所以问题是:
- 缺少的 "X-" 有什么意义吗?
- 如何将令牌的加密版本更改为普通版本? (不管问题 #3)
- 我是应该尝试从加密令牌中制作一个普通令牌,还是加密
csrf_token()
更好? (这有关系吗,因为连接是加密的?) - 在
\MiddleWare\EncryptCookies.php
中的$excepted
下列出 "XSRF-TOKEN" 是一个可行的选择,还是您可以建议更好的解决方案? (这让我们回到了问题 #3)
很抱歉提出这么多问题,在此先感谢您!
编辑
我的问题重读了好几遍后,我得出的结论是,它们不够清楚,与标题不符。我的问题是令牌不匹配,我认为清除我的疑虑会引导我找到解决方案,我感谢@ThomasMoors 的耐心和帮助。我会接受他的回答,虽然我用不同的方式解决了我的问题,但正是他的帮助让我找到了解决方案!我还发布了我自己的答案,描述了我如何解决我的问题以帮助其他有类似问题的人!
The function that checks the token tries to find it (1) inside a request plain with the key _token
, if it does not find it, it will try to look inside (2) the request headers with the key X-CSRF-TOKEN
. The token to match is stored inside the session, where the session lives depends on your config.
/**
* Determine if the session and input CSRF tokens match.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function tokensMatch($request)
{
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
if ( ! $token && $header = $request->header('X-XSRF-TOKEN'))
{
$token = $this->encrypter->decrypt($header);
}
return StringUtils::equals($request->session()->token(), $token);
}
Q: 缺失的"X-"有什么意义吗?
A: Laravel stores the current CSRF token in a XSRF-TOKEN cookie that is included with each response generated by the framework. You can use the cookie value to set the X-XSRF-TOKEN request header.
This cookie is primarily sent as a convenience since some JavaScript frameworks and libraries, like Angular and Axios, automatically place its value in the X-XSRF-TOKEN header.
Q: 如何将令牌的加密版本更改为普通版本? (不管问题 #3)
A:如上面的代码(来自 github)\Illuminate\Contracts\Encryption\Encrypter
有一个名为 decrypt()
的函数可以执行此操作
Q: 我是应该尝试用加密的令牌制作一个普通令牌还是加密 csrf_token() 更好? (这有关系吗,因为连接是加密的?)
A: 没关系,因为令牌里面没有数据,它只是来自您站点的合法请求的标识符,而不是某些 ajax/xhr 从另一个域调用。阅读更多关于 https://en.wikipedia.org/wiki/Cross-site_request_forgery
Q:是否在 \MiddleWare\EncryptCookies.php 中的 $excepted 下列出 "XSRF-TOKEN" 一个可行的选项或者可能你建议一个更好的解决方案吗? (这让我们回到了问题 #3)
A: 令牌没有理由在任何时候都在 cookie 中,对吗?
更新
看来从5.0到5.4确实是上面函数中的东西has changed。现在看起来像这样:
protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);
return is_string($request->session()->token()) &&
is_string($token) &&
hash_equals($request->session()->token(), $token);
}
虽然我无法确定问题的根源(由于缺乏使用框架的经验),但我终于可以解决我的问题。到目前为止我错过的是一些 中间件 类 被移动到 app/Http/Kernel.[=23= 中的不同中间件组] 文件(我的问题可能是因为 它们的加载顺序 发生了变化,或者可能是因为其中一些根本没有加载?)。我很确定,这是我的问题的原因,因为我不断地重新加载我的页面并清除缓存,就像 github 上建议的那样,这是 jeremykenedy 的建议。建议调用以下命令:
sudo rm -rf storage/framework/sessions/*
sudo php artisan cache:clear
sudo php artisan clear-compiled
sudo composer dump-autoload
你们所有处理类似问题的人可能已经遇到过数百次了。我经常发现的另一个建议是更改存储文件夹的权限,这可能有助于你们中的一些人解决类似的问题!
我发现了一个关于令牌不匹配异常的有趣的事情。我在 AppServiceProvider 中将约会时间伪造为:
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Carbon::setTestNow('2000-07-05 4:00 pm');
}
之后我无法登录我的 laravel 应用程序。否则只需一个命令就足以解决令牌不匹配异常。
php artisan config:clear