csrf Token未生效需检查@csrf是否被渲染、api路由是否误入web中间件组、csrf_token()与@csrf使用场景差异及nginx下session配置问题。

CSRF token没生效?检查 @csrf 是否真被渲染
laravel 默认开启 CSRF 保护,但表单里漏掉 @csrf 或它被注释/条件屏蔽了,就等于裸奔。常见现象是提交表单时直接报 419 Page Expired 或 TokenMismatchException——其实不是 token 过期,而是压根没发 token。
实操建议:
- 用浏览器“查看网页源代码”,确认表单 HTML 中确实存在类似
<input type="hidden" name="_token" value="xxx">的字段 - 不要在 Blade 中写
@if(false) @csrf @endif这类逻辑,@csrf必须无条件执行 - ajax 请求需手动取值:从
meta[name="csrf-token"]标签读content属性,再塞进请求头X-CSRF-TOKEN
Laravel 10+ 的 VerifyCsrfToken 中间件怎么排除接口
API 路由默认不走 CSRF 验证,但如果你把 API 放在 web 中间件组里(比如用 Route::middleware('web') 包裹了 /api/*),CSRF 就会强制校验,导致 POST 接口失败。
实操建议:
- 确认路由是否真的在
routes/api.php——只有这里的路由才自动跳过VerifyCsrfToken - 若必须在
web.php里写 API(比如调试用),在中间件中排除:$except = ['debug-api/*'] - 别在
$except里写正则或模糊路径,只支持前缀匹配,例如'v1/users'有效,'v1/*/create'无效
csrf_token() 和 @csrf 有什么区别?什么时候该用哪个
两者都生成 token 字符串,但使用场景和安全性边界不同。@csrf 是 Blade 指令,会自动输出完整 input 标签;csrf_token() 只返回字符串,常用于 js 或自定义表单构造。
实操建议:
- 普通 Blade 表单一律用
@csrf——少出错,且 Laravel 未来可能加额外防护逻辑 - JS 动态提交时,优先读
meta[name="csrf-token"](Laravel 自动注入),而不是调用csrf_token()函数,避免多次执行产生新 token 导致旧 token 失效 - 不要在 Vue/React 组件里直接写
{{ csrf_token() }}——服务端渲染时 token 已生成,客户端再取会不一致
为什么本地开发正常,部署到 Nginx 后 CSRF 总失效
本质是 session 未正确保存或跨域丢失,不是 CSRF 本身的问题。典型表现:首页能刷出 token,但提交时提示 token 不匹配,或者每次刷新页面 token 都变(说明 session 没写入)。
实操建议:
- 检查
config/session.php中的domain配置:线上环境若配了.example.com,但访问的是www.example.com或裸域名,cookie 就不会携带 - Nginx 需透传 Cookie:确认没有
proxy_pass_request_headers off,且proxy_cookie_path未错误重写 path - 确保
storage/framework/sessions/目录可写,且磁盘没满——session 写失败时 Laravel 不报错,只静默 fallback 到 Array 驱动(即不持久化)
CSRF 不是开关式功能,它依赖 session、路由分组、中间件顺序、前端 token 传递路径四个环节咬合。任一环松动,验证就断在你看不见的地方。