laravel集成cloudflare turnstile核心是前端获取token并提交、后端调用siteverify接口校验;须禁用第三方包,直接在blade中嵌入原生widget并用http::asform()->post()严格验证success字段与http状态码,同时防范空token、域名不匹配、ip透传缺失等绕过风险。

直接说结论:Laravel 项目里集成 Cloudflare Turnstile,核心就两件事——前端拿到 turnstileToken 并随表单提交,后端用 Http::asForm()->post() 调用 Cloudflare 的 https://challenges.cloudflare.com/turnstile/v0/siteverify 接口校验。别碰任何第三方 Laravel 包,它们要么过时,要么硬塞中间件破坏原生请求流程。
怎么在 Laravel 表单里嵌入 Turnstile widget
不要用 npm install 或 blade 组件封装,直接在 Blade 模板里写原生 HTML + JS:
- 确保页面已加载官方脚本:
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> - 在表单内插入 widget 容器,
data-sitekey必须是 Cloudflare 控制台生成的正式 sitekey(开发模式下可用1x00000000000000000000AA测试) - 用
data-callback触发 token 注入隐藏字段,避免手动取值时机错乱
示例代码:
<script> function onTurnstileSuccess(token) { document.getElementById('cf_turnstile_response').value = token; } </script>Laravel 后端如何安全校验 turnstileToken
关键不是“怎么发请求”,而是“怎么防止绕过”和“怎么处理失败”。Cloudflare 返回的 success: true 才算通过,其余都得拒绝,包括 success: false、error-codes 数组非空、HTTP 状态码非 200。
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
- 必须用
Http::timeout(5)->asForm()->post(),不能用 Guzzle 手动拼 body,否则容易漏掉Content-Type: application/x-www-form-urlencoded -
secret和response是仅有的两个必传参数,remoteip可选但建议传(从$request->ip()取) - 不要在 Form Request 的
rules()里做校验——那里拿不到原始 request body,且无法捕获网络异常
推荐放在 Controller 方法开头校验:
$response = Http::timeout(5)
->asForm()
->post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
'secret' => config('services.cloudflare.secret_key'),
'response' => $request->input('cf_turnstile_response'),
'remoteip' => $request->ip(),
]);
if (! $response->successful() || ! $response['success']) {
return back()->withErrors(['cf_turnstile_response' => '验证失败,请重试']);
}
常见错误和绕过风险点
很多人卡在“明明 token 有效却一直失败”,根本原因不是代码写错,而是环境或配置断层:
-
400 Bad Request:多半是secret值为空或含不可见字符(复制时带了全角空格),检查config/services.php里是否用了双引号包裹且没转义 -
403 Forbidden:Cloudflare 控制台里该 sitekey 绑定的域名不匹配当前请求 Host,注意example.com≠www.example.com - 本地开发时 token 总是
success: false:确认没在 .env 里误设APP_ENV=production,导致 Laravel 自动加了 HTTPS 强制跳转,而 Turnstile widget 加载失败 - 攻击者删掉 hidden input 提交空 token:必须在 Controller 校验前加
required|string|min:100规则,否则$request->input()返回 null 会触发空 secret 请求
真正难的是行为一致性——比如你用 Nginx 做了 IP 透传但忘了配 real_ip_header X-Forwarded-For,后端拿到的 $request->ip() 就是负载均衡地址,和 Turnstile 挑战时的 IP 不一致,token 直接作废。这种链路级问题,光看 PHP 代码永远定位不到。










