Laravel 419 错误-VerifyCsrfToken 问题
Posted
技术标签:
【中文标题】Laravel 419 错误-VerifyCsrfToken 问题【英文标题】:Laravel 419 Error - VerifyCsrfToken issue 【发布时间】:2019-03-16 19:16:57 【问题描述】:我在同一台服务器上托管了多个 Laravel 站点。在我创建的最新站点中,联系表单拒绝提交而不会引发 419 错误。我已经在我的 web.php 文件中设置了路由,就像其他网站一样,这些网站具有实时、有效的联系表单,并且我生成和发送令牌的方式完全相同 - 使用 csrf_field()
。
我找到了一个类似问题的答案,指出您可以通过将条目添加到 app/Http/Middleware/VerifyCsrfToken.php
中的 $except
数组来禁用 Csrf 检查。我已经验证这确实解决了 419 错误:
protected $except = [
'contact',
'contact*',
];
但我当然希望保留 Csrf 功能,并且我只更新了 $except
数组以用于故障排除值。
有谁知道尽管传递了生成的令牌,但新的 Laravel 环境可能会有这种 419 行为的不同之处?我已经尝试更新许多 ENV 设置并切换不同的东西,但除了修改 $except
数组之外没有其他任何影响。
更新
由于到目前为止已经进行了一些讨论,我想我会提供一些额外的信息和代码。
首先,这是一个 ajax 表单,但现在不要跳出你的座位。我一直在测试有无 ajax 的表单。如果我想使用 ajax 进行测试,我只需单击连接到 jQuery 侦听器的按钮。如果没有,我更改或删除按钮的 ID,或在控制台窗口中运行 $("#formName").submit();
。
上述(ajax、老式提交和带有.submit();
的 jquery 选择器)都导致完全相同的响应 - 419 错误。
为了完整起见,这是我的 ajax 代码,它可以在我托管的所有其他网站上运行。我定义了一个 postData 数组来保持它的整洁,并在它之后直接添加了一个 console.log()
语句,以(再次)确认令牌生成得很好并且与请求一起正确传递。
var postData =
name: $("#name").val(),
email: $("#email").val(),
message: $("#message").val(),
_token: $("input[name=_token]").val()
;
console.log(postData);
$.post("/contact", postData, function (data)
...
有什么想法吗?我的 ENV 或其他文件是否存在配置问题?
进度更新!
因为其他站点运行良好,所以我克隆了一个旧站点并简单地覆盖了我为新站点更改的文件,然后 bam!它现在正在工作。进行了更多挖掘,我在站点的克隆版本与非工作版本上运行了php artisan --version
,结果如下:
工作版本:Laravel 框架 5.7.3
非工作版本:Laravel Framework 5.7.9
也许这是 Laravel 的一个错误?或者我服务器上的某些包已经过时,需要更新才能与新版本的 Laravel 一起使用?
【问题讨论】:
假设 CSRF 验证我猜你已经在 web.php 而不是在 api.php 中设置了这些路由? 是的,在web.php
我有以下两条路线:Route::get('/contact', 'ContactController@index');
和Route::post('/contact', 'ContactController@contactSubmit');
您是否看到 _token
值被发送到 POST 路由? dd($request->all())
在contactSubmit
函数中,并确保它被正确发送。
我在发布这个问题之前添加了dd($request->all())
,并且在我的本地开发环境中它正确显示了json输出,包括_token
。但是,在服务器上,它甚至不会到达dd()
,因为它在执行contactSubmit()
方法中的第一行代码之前就抛出了419 错误。但是我服务器上托管的其他网站上的其他联系表格可以正常工作,没有任何问题。
@Chad 您是否看到_token
在浏览器的网络检查器的“网络”选项卡中随请求一起发送?
【参考方案1】:
TLDR:这篇文章包含许多潜在的问题和修复;它适用于那些在卡住时搜索相关奖励信息的人。
我刚刚在使用 Laravel Sanctum 时遇到了这个错误,看起来好像没有正确设置中间件。 Sanctum 使用 auth:sanctum
中间件作为守卫,这是 Laravel 默认使用的 auth
守卫的某种扩展,但会话由 web
中间件组处理。
我无法准确描述一些 Laravel 内部的东西;目前我在 javascript 方面的经验比 PHP 更丰富。
在我的api.php
文件中,我有登录/注册/注销路由,在我的Kernel.php
文件中,我将\Illuminate\Session\Middleware\StartSession::class,
从 web 组复制到了 api 组。
我必须这样做来修复我的登录单元测试,该测试引发了关于“会话存储未按请求”的错误。复制它让我的postJson
请求可以在单元测试中工作,但过了一段时间,我开始看到 JavaScript 应用程序发布 419 CSRF 错误(这很糟糕,因为它之前运行良好)。
我开始在 /storage/framework/sessions
文件夹中寻找一些文件系统权限,但问题不在于(对我而言)。
我后来发现,对于 Laravel Sanctum 和默认的 AuthenticatesUsers
特征,您必须使用 web
保护来进行身份验证,并使用 auth:sanctum
中间件来保护路由。我试图将 api
保护用于身份验证路由,这是我的 AuthenticatesUsers 特征出现 419 错误的核心。
如果有人在 CSRF 工作或应该工作时收到 419,我建议在系统中需要这些工作的所有关键点进行一些 \Log::debug()
调查:
Auth::check()
Auth::user()
Auth::logout()
如果你对这些有奇怪的行为,根据我的观察,你与sessions
相关的配置有问题,或者你与web
、api
守卫相关的配置有问题。
守卫与AuthManager
守卫有关,它维护多个请求和多个单元测试的状态。
这是我找到的最好的描述,我花了一个多星期才发现:
Method Illuminate\Auth\RequestGuard::logout does not exist Laravel Passport
作为最后一个随机示例,如果您的会话以某种方式使用来自 web
中间件组的数据生成 CSRF 令牌,而您的路由设置为使用 api
,则它们可能会错误地解释收到的 CSRF。
除此之外,打开 Chrome 开发工具并转到“应用程序”选项卡,然后查看 cookie。确保 XSRF-TOKEN
cookie 不安全(即:不是 httpOnly)。
这将允许您拥有这样的 Axios 请求拦截器:
import Cookies from 'js-cookie';
axios.interceptors.request.use(async (request) =>
try
const csrf = Cookies.get('XSRF-TOKEN');
request.withCredentials = true;
if (csrf)
request.headers.common['XSRF-TOKEN'] = csrf;
return request;
catch (err)
throw new Error(`axios# Problem with request during pre-flight phase: $err.`);
);
这就是我当前的 Laravel/Vue SPA 是如何成功运行的。
过去,我在这里也使用过这种技术:
app.blade.php(根布局文件,文档头)
<meta name="csrf-token" content=" csrf_token() ">
bootstrap.js(或任何地方)
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
const token = document.head.querySelector('meta[name="csrf-token"]');
if (token)
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
else
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
在我看来,大多数问题都源于以下一个或多个文件中的值不正确:
./.env
./config/auth.php
./config/session.php
密切关注诸如 SESSION_DOMAIN、SESSION_LIFETIME 和 SESSION_DRIVER 之类的东西,就像我说的,文件系统权限。
检查您的 nginx access.log
和/或 error.log
文件;它们可能包含提示。
【讨论】:
【参考方案2】:刚刚在框架回购中发现了您的问题。 这不是 laravel 问题,您的安装缺少存储文件夹的写入权限,因此 laravel 无法写入会话、日志等。
您收到 419 错误,因为您无法写入文件,因此您无法创建会话,因此您无法验证 csrf 令牌。
快速修复:chmod -R 777 storage
正确的解决方法:将您的安装移动到 nginx/apache/您的用户实际可以写入的文件夹。
如果您使用的是 nginx/apache,请将您的应用程序移到那里并授予项目 (chown -R www-data: /path-to-project)
的正确权限
如果您使用的是 php artisan serve,请将其权限更改为您的用户:chown -R $(whoami) /path-to-project
你明白了,让作家写作,你很好。
【讨论】:
我正在使用数据库驱动程序,但仍然有这个问题。【参考方案3】:运行这个命令 php工匠密钥:生成
【讨论】:
【参考方案4】:可能您在浏览器地址栏中的域与 domain
配置文件中的 domain
键或 env 文件中的 SESSION_DOMAIN
不匹配。
【讨论】:
【参考方案5】:我有同样的问题,但我的问题是 https。表单在 http 页面上,但操作在 https 上。结果会话不一样,导致csrf错误。
【讨论】:
【参考方案6】:我为 staging 和 prod 使用了相同的应用程序名称,作为 prod 的子域。在暂存中更改应用程序名称后,它起作用了
【讨论】:
以上是关于Laravel 419 错误-VerifyCsrfToken 问题的主要内容,如果未能解决你的问题,请参考以下文章
Vue + Laravel sanctum CSRF 令牌不匹配 419 错误