laravel post 请求 csrf 验证失败本质是请求未通过校验流程,主因在中间件配置、路由分组或服务器拦截;需区分 api 与 web 路由、正确配置 $except 数组、前端携带 x-csrf-token,并排查服务器层丢弃 post。

确认是不是真需要 CSRF 校验
API 路由(routes/api.php)默认不该走 CSRF 校验——但如果你用浏览器 fetch 或 Axios 调用,且启用了 Sanctum 的 SPA 认证(EnsureFrontendRequestsAreStateful),它会自动把前端请求当作“有状态”处理,悄悄拉起 session 和 CSRF 校验。
- 纯前后端分离 API(如 Vue/React 独立部署、调用
/api/xxx)→ 应禁用 CSRF,不依赖 session - 传统 Blade 页面内发起的表单或 AJAX → 必须保留 CSRF,靠
@csrf或X-CSRF-TOKEN头传递 - SPA + Sanctum 登录态维持 → 需确保
SESSION_DOMAIN和APP_URL域名一致,且前端正确携带X-XSRF-TOKENcookie
快速排除:先看中间件是否误伤
打开 app/Http/Kernel.php,检查你的 POST 路由实际套用了哪组中间件:
-
web中间件组含VerifyCsrfToken→ 所有非 GET/HEAD/OPTIONS 的请求都强制校验 -
api中间件组不含VerifyCsrfToken,但含EnsureFrontendRequestsAreStateful→ 它会在检测到Origin头时“复活” CSRF 校验
✅ 推荐做法:在 app/Http/Middleware/VerifyCsrfToken.php 的 $except 数组中明确排除 API 路径:
protected $except = [
'api/*',
'sanctum/csrf-cookie', // 必须保留该入口用于获取初始 token
];
注意:api/* 是前缀匹配,Laravel ≥ 9.23 支持;旧版本建议写 'api/' 或逐条列出关键接口(如 'api/login')。
前端必须做对的三件事
即使后端放行,前端漏掉任意一环也会触发 419:
- 页面
中存在<meta name="csrf-token" content="{{ csrf_token() }}"> - JS 发起请求前,从该 meta 标签读取 token,并设为请求头:
headers: { 'X-CSRF-TOKEN': token } - 使用 Axios 时,别只设
X-Requested-With,必须设X-CSRF-TOKEN;用 fetch 则需手动添加
⚠️ 特别提醒:Vite 或纯静态 HTML 页面不会渲染 Blade 的 {{ csrf_token() }},此时应改用 Sanctum 的 /sanctum/csrf-cookie 接口预取 token,再发业务请求。
别忽略服务器层拦截
本地正常、线上 419?大概率是 Web 服务器或安全模块(ModSecurity、Cloudflare WAF、cPanel 防护)静默丢弃了 POST 请求。
- 查 Nginx/Apache 的 error log,搜关键词
ModSecurity、rejected、POST - 临时关闭 WAF 测试;若恢复,则加白名单规则(如放行
/api/*或特定 POST 路径) - 确认
php.ini中post_max_size和upload_max_filesize足够大,超限会导致请求体为空,CSRF 校验无 token 可验











