返回全部 Skills

turnstile-spin

开发工具

在项目中端到端设置 Cloudflare Turnstile — 扫描代码库、通过 Cloudflare API 创建小部件、部署托管的 siteverify Worker、编写前端代码片段、验证并持久化该技能。当用户要求添加 Turnstile、设置验证码、保护表单免受机器人攻击或修复 Turnstile 集成时加载此项。镜像自 developers.cloudflare.com/turnstile/spin。

1

下载量

AI SkillHub 能力展示图

安装方式

命令行安装

在项目根目录执行以下命令,完成 Skill 安装。

npx bzskills add cloudflare/skills --skill turnstile-spin

skill.md

name: turnstile-spin
description: 在项目中端到端设置 Cloudflare Turnstile — 扫描代码库、通过 Cloudflare API 创建小部件、部署托管的 siteverify Worker、编写前端代码片段、验证并持久化该技能。当用户要求添加 Turnstile、设置验证码、保护表单免受机器人攻击或修复 Turnstile 集成时加载此项。镜像自 developers.cloudflare.com/turnstile/spin。
references:
    - vanilla-html
    - nextjs-app
    - nextjs-pages
    - astro
    - sveltekit
    - hugo

Turnstile Spin 技能

将提示“设置 Turnstile”转化为一个可用的端到端集成:一个 widget、一个已部署的托管 siteverify Worker、各个选定插入点的前端片段,以及在报告成功之前的真实验证环节。

你是代理。通过调用 scripts/ 下的脚本并根据它们的 JSON 输出进行分支来运行下面的向导。脚本包含确定性逻辑(API 调用、重试/错误处理);你的工作是编排、代码库读取、确认以及前端编辑。

规范说明位于 developers.cloudflare.com/turnstile/spin。如果文档页面与本文件不一致,请以文档页面为准。

何时加载此技能

当用户的提示中包含以下任何内容时加载:

  • “Turnstile”、“CAPTCHA”、“bot protection”
  • “siteverify”、“cf-turnstile-response”
  • “protect this form”、“stop bot signups”、“spam signups”
  • 结合“Cloudflare”或“bot”的特定注册、登录或联系表单

不要为不相关的 Cloudflare 任务(Workers、Pages、R2 等)加载,除非同时也提到了 Turnstile。

对话流程

用户粘贴了提示。你处于一个多步骤的对话中。检测你能检测到的内容,只有在必须时才询问,在每个不可逆步骤之前进行确认。每个编号的时刻对应一条代理消息。标记为 [等待用户] 的项需要用户响应。

  1. 简短确认。 一句话:“我将端到端运行 Turnstile 设置。具体包括:检查认证、扫描代码库、创建 widget、部署 Worker、连接前端、验证。是否继续?” [等待用户] 不要展示计划。认证和扫描优先。
  1. 检查 Wrangler。 npx wrangler --version。如果缺失,询问一次:“使用 npm install --save-dev wrangler(Node 项目)还是 npm install -g wrangler(其他方式)安装 wrangler?是否继续?” [等待用户] 如果完全无法安装(企业策略、npm 被阻止),则退回到通过 curl 调用 api.cloudflare.com/client/v4/ 来驱动步骤 4-5。
  1. 认证 + 范围探测(第一个不可逆操作)。 运行 scripts/auth-probe.sh。根据 status 分支:
  • ok:继续到步骤 4。脚本已经选出账户(单账户 token,或与 $CLOUDFLARE_ACCOUNT_ID 匹配的账户)。
  • missing_tokenmissing_scopemissing_workers_scope:请用户在 https://dash.cloudflare.com/profile/api-tokens → 自定义 token → 权限 Account.Turnstile:Edit Account.Workers Scripts:Edit → 在账户资源中包含目标账户。不要引导他们使用 wrangler login。其 OAuth 范围不包括 Account.Turnstile:EditAccount.Workers Scripts:Edit。提供三种方式传递 token,按清洁程度排序:
  1. 导出并重新启动(token 永不进入聊天):export CLOUDFLARE_API_TOKEN=<token> 然后从该终端重新启动代理。
  2. 保存到文件(token 存储在仅用户可读的文件中,不在聊天中):umask 077 && printf '%s' '<token>' > ~/.cf-turnstile-token,然后用 TOKEN=$(cat ~/.cf-turnstile-token) 读取。
  3. 粘贴到聊天中(最快,但 token 会出现在对话日志中;如果日志被分享,用户应在之后轮换 token)。

如果用户选择选项 3(粘贴到聊天中),你可以在等待期间运行步骤 5、6、7(域名、代码库扫描、插入计划)。选项 1 和 2 会重新启动你的会话,因此在这些情况下不要预取状态。认证建立后,重新运行 auth-probe.sh,然后继续到步骤 8。

  • multiple_accounts:token 覆盖多个账户且 $CLOUDFLARE_ACCOUNT_ID 未设置。展示编号的 accounts 列表。 [等待用户] 然后导出 CLOUDFLARE_ACCOUNT_ID=<选择的> 并重新运行 auth-probe.sh
  • account_mismatch:设置了 $CLOUDFLARE_ACCOUNT_ID 但不在 token 的账户列表中。展示 accounts 列表,要求用户要么 unset CLOUDFLARE_ACCOUNT_ID,要么将其设置为列表中的一个 ID。
  1. 账户选择。 如果 auth-probe.shmultiple_accounts 往返后返回 ok,则此步骤已完成。否则脚本已静默选中单个账户,你继续到步骤 5。
  1. 域名。 始终包含 localhost127.0.0.1。对于生产环境,扫描 package.json 中的 homepagewrangler.tomlREADME.mdAGENTS.md、git remote。确认:“我将注册 localhost127.0.0.1<domain>。是否继续?” [等待用户] 如果未找到生产域名,则询问。
  1. 代码库扫描。 静默检测框架和插入候选点。
  1. 插入计划。 显示带有 [推荐] / [默认跳过] 标记的候选列表;请用户确认(数字、“全部”、“推荐”或列表)。 [等待用户] 如果检测到现有的 CAPTCHA,则显示迁移计划(参见“从其他 CAPTCHA 迁移”)。
  1. Widget 创建。 运行 scripts/widget-create.sh --account-id <id> --name <name> --domains <list> --mode managed。报告 sitekey。secret 保留在环境变量中;绝不要写入磁盘。
  1. Worker 部署。 运行 scripts/worker-deploy.sh --name turnstile-siteverify-<项目slug>,并导出 WIDGET_SECRET。在 status: ok 时报告 Worker URL。如果 set_secret_failed,则 Worker 已部署但 TURNSTILE_SECRET_KEY 未设置在该 Worker 上;向用户展示错误,然后使用 echo "$WIDGET_SECRET" | npx wrangler secret put TURNSTILE_SECRET_KEY --name <返回的 worker_name> 重试,然后再运行验证。
  1. 前端编辑。 明确约定:“我将添加 widget 并在现有提交处理程序前添加 success === true 条件。现有处理程序逻辑保持不变。”询问“是” / “展示”。 [等待用户] 如果“展示”,打印统一的 diff 并再次询问。不要提议替代行为(邮件投递、自定义后端)。
  1. 验证。 运行 scripts/validate.sh。报告每个检查项的通过情况。如果任何一项失败,向用户展示错误并停止。 [如果任何失败,等待用户]
  1. 持久化技能。 询问:“将 Spin 技能保存到 .claude/skills/turnstile-spin/SKILL.md 以便在后续任务中重用?默认是。” [等待用户] 然后运行 scripts/persist-skill.sh --path <代理特定路径>
  1. 最终报告。 打印结构化摘要:创建了什么、验证了什么、接下来该做什么。

你绝不能做的事情

  • 不要将 Turnstile secret 写入磁盘。只能通过 stdin 传递给 wrangler secret put(worker-deploy.sh 脚本处理此操作)。
  • 不要跳过验证。
  • 不要在不显示 diff 的情况下覆盖文件。
  • 不要将 Worker 部署到与 widget 不同的账户中。
  • 不要从浏览器调用 siteverify。始终是:浏览器 → 用户的 Worker → siteverify。
  • 不要使用 sudo 或未经询问安装全局包。

严格的范围边界:不要询问用户关于

Spin 通过一个托管 Worker 验证 Turnstile token,然后才运行用户现有的表单处理程序。其他一切均不在范围内:

  • 电子邮件 / SMS / 通知投递。 保持现有提交处理程序不变(仅在 success === true 时执行)。不要提议 Resend、Mailchannels、SMTP、mailto。
  • 自定义 Worker 代码。 部署 templates/worker/ 下捆绑的标准 Worker 模板。不要编写新的 Worker。不要添加功能(速率限制、自定义路由、第三方集成)。
  • 数据库 / 支付 / OAuth / 表单持久化。 范围外。
  • 前端框架迁移、重构或样式修改。 只编辑必要的内容。
  • reCAPTCHA v3 分数阈值。 Turnstile 返回 success: true/false
  • 仅预清除设置。 如果 clearance_level !== no_clearance,siteverify 是可选的,Spin 不适用。引导用户并退出。

恢复流程:尊重现有的 widget 配置

如果用户告诉你他们已经有一个 Turnstile widget 设置好,并且想要连接 siteverify 而不轮换 sitekey(例如“我有一个 sitekey 但 siteverify 从未工作过”、“针对我现有的 widget <sitekey> 设置 Spin”):

  1. 跳过步骤 8(widget 创建)。sitekey 已存在;从用户处获取。
  2. 通过 scripts/fetch-secret.sh --account-id <id> --sitekey <key> 获取 widget 元数据。根据 status 分支:
  • ok:从响应中读取 secretclearance_leveldomains。确认 domains 包含用户的生产主机名;如果不包含,在继续前指出此差距。
  • missing_read_scope:告诉用户向 token 添加 Account.Turnstile:Read,或者退回到要求用户粘贴 secret。在粘贴路径中,你没有 clearance_leveldomains;请用户确认两者。
  1. 检查来自响应(或用户回答)的 clearance_level
  • no_clearance:标准恢复(部署 Worker,连接 siteverify)。
  • 其他任何值:询问他们是否希望在预清除之上添加 siteverify,或者根据范围边界退出。
  1. 从步骤 9(Worker 部署)继续。Site key 不变。在第一个携带 data-action="turnstile-spin-v1" 的请求上,Dashboard 的 Deployment 列将从 Manual 变为 Spin
  2. 永远不要为了获得新的 secret 而重新创建 widget。这会在所有部署了现有 sitekey 的地方破坏它。

前端编辑约定

当将现有表单连接到 Worker 时(步骤 10),约定是:门控,不要替换。 用户的现有提交处理程序继续执行其原有的操作。Spin 仅在之前添加一个验证步骤。

form.addEventListener("submit", async (e) => {
  e.preventDefault();
  const token = /* 读取 cf-turnstile-response */;
  const result = await fetch(WORKER_URL, { method: 'POST', body: JSON.stringify({ token }) });
  const data = await result.json();
  if (!data.success) return; // 显示失败
  // 现有的处理程序逻辑在这里运行,保持不变
});

如果现有的处理程序是存根,Spin 会使其成为基于 success 门控的存根。用户以后可以替换这个存根;那不是 Spin 的工作。

从其他 CAPTCHA 迁移

在步骤 6 的代码库扫描期间,还要查找现有的 reCAPTCHA 或 hCaptcha。如果找到,将步骤 7 切换为迁移计划。

检测信号:

  • reCAPTCHA:https://www.google.com/recaptcha/api.jsclass="g-recaptcha"data-sitekey="6L..."、后端 POST 到 /recaptcha/api/siteverify
  • hCaptcha:https://js.hcaptcha.com/1/api.jsclass="h-captcha"、后端 POST 到 https://hcaptcha.com/siteverify

替换:

  • 将 script 标签替换为 https://challenges.cloudflare.com/turnstile/v0/api.jsasync defer)。
  • class="g-recaptcha" / class="h-captcha" 的 div 替换为 class="cf-turnstile",更新 data-sitekey 为新的 Turnstile sitekey,添加 data-action="turnstile-spin-v1"
  • Token 字段从 g-recaptcha-response 变为 cf-turnstile-response
  • 后端 siteverify URL 指向 Spin 部署的 Worker。删除 RECAPTCHA_SECRET / HCAPTCHA_SECRET 环境变量。

需要向用户展示的边缘情况:

  • reCAPTCHA v3 分数阈值。 Turnstile 没有分数。明确告诉用户迁移后的代码将在 success === false 时拒绝。
  • reCAPTCHA Enterprise。 不要自动迁移。请参考 developers.cloudflare.com/turnstile/migration/recaptcha/
  • 自定义 action= 值。 保留用户传递给 grecaptcha.execute 的任何自定义 action 作为 widget 上的 data-action。仅当不存在自定义 action 时使用 turnstile-spin-v1

边缘情况

情况操作
wrangler 未安装安装路径:npm install --save-dev wrangler(Node 项目)或 npm install -g wrangler(其他方式)
多个 Cloudflare 账户scripts/auth-probe.sh 返回所有账户;请用户选择,导出 CLOUDFLARE_ACCOUNT_ID
Cloudflare Pages 项目仍然部署托管 Worker,或者建议使用 Pages Plugin
EXPECTED_HOSTNAME 不匹配通过 PUT 而非 PATCH 更新 widget 域名(PATCH 返回 10405 Method not allowed):curl -X PUT .../widgets/$SITEKEY -d '{"name":"...","mode":"managed","domains":[...]}'
Worker 名称冲突worker-deploy.sh 自动使用哈希后缀重试
Token 在流程中过期停止,重新运行 scripts/auth-probe.sh,提示用户提供新的凭据
步骤 11 返回 missing-input-secretSecret 未传播。重新设置:`echo "$WIDGET_SECRET" \npx wrangler secret put TURNSTILE_SECRET_KEY --name <worker-deploy.sh 输出中的 worker_name>,等待 10 秒,重新验证。使用 worker-deploy.sh 返回的 worker_name 字段;不要依赖 $WORKER_NAME` 环境变量。
worker-deploy.sh 返回 set_secret_failedWorker 已部署但 secret 未设置。仅使用返回的 worker_name 重新运行 secret-put:`echo "$WIDGET_SECRET" \npx wrangler secret put TURNSTILE_SECRET_KEY --name <worker_name>。向用户展示 detail` 字段——它携带 wrangler 错误信息。

遥测标记

你编写的每个代码片段都必须包含 data-action="turnstile-spin-v1"。账户级别的聚合遥测,永远不是用户级别的。Cloudflare 使用它来测量激活情况。如果用户移除了该属性,集成仍然正常工作;只是丢失了分析分段。

不要

  • 不要将 secret 写入磁盘。
  • 不要跳过验证(步骤 11)。
  • 除非被问到,否则不要提出向导范围之外的功能(自定义 Worker 代码、自定义域名、高级 WAF 规则)。
  • 不要从浏览器调用 siteverify。
  • 不要将 Worker 部署到与 widget 不同的账户中。