开发文档/人机验证

人机验证对接文档

完全免费,任何网站都能用,用法与 Cloudflare Turnstile 一致。

简介

在注册、登录、发验证码等页面放一个验证挂件,访客点一下就拿到 token;你的后端核验 token 后再处理请求。 任何网站都能用,只在你调用的地方生效,不影响 App 和对外 API。

三步接入

步骤做什么
1. 创建密钥在控制台「人机验证」创建,得到 Site Key(前端用)和 Secret(后端用)
2. 前端嵌入引入脚本,放一个挂件容器,访客通过后拿到 token
3. 后端核验用 Secret 和 token 调核验接口,success 为 true 才放行
💡
控制台创建密钥后会直接给出填好 Site Key 的代码,复制即可。下文的 pk_你的SiteKey 换成你的 Site Key,Secret 放在服务端环境变量 WAFBI_CAPTCHA_SECRET。

前端嵌入

普通表单

引入脚本,在表单里放一个带 wafbi-captcha class 的容器。验证通过后,表单会自动带上隐藏字段 wafbi-captcha-response,后端从这个字段取 token。

register.html
<script src="https://captcha.waf.bi/__captcha/api.js" async defer></script>

<form action="/register" method="POST">
  <input name="email" type="email" />
  <div class="wafbi-captcha" data-sitekey="pk_你的SiteKey"></div>
  <button type="submit">注册</button>
</form>
<!-- 验证通过后,表单自动带上隐藏字段 wafbi-captcha-response -->

前后端分离(Vue / React 等)

用 wafbiCaptcha.render 手动渲染,通过回调或 getResponse 拿 token,自己放进请求体。每个 token 只能核验一次,提交后调用 reset。

login.html
<script src="https://captcha.waf.bi/__captcha/api.js" async defer></script>
<div id="captcha"></div>

<script>
let widgetId
window.addEventListener('load', () => {
  widgetId = wafbiCaptcha.render('#captcha', {
    sitekey: 'pk_你的SiteKey',
    callback: (token) => { /* 验证通过,token 约 5 分钟内有效 */ },
    'expired-callback': () => { /* token 过期,挂件已自动重置 */ },
    'error-callback': (code) => { /* 例如 rate-limited */ },
  })
})

async function login(email, password) {
  const res = await fetch('/api/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password, captcha: wafbiCaptcha.getResponse(widgetId) }),
  })
  wafbiCaptcha.reset(widgetId) // token 只能核验一次,提交后重置
  return res
}
</script>

选项与方法

JS 选项HTML 属性说明
sitekeydata-sitekey必填,密钥的 Site Key
callbackdata-callback验证通过时调用,参数为 token
expired-callbackdata-expired-callbacktoken 过期时调用(约 5 分钟)
error-callbackdata-error-callback验证失败时调用,参数为错误码
response-field-namedata-response-field-name表单隐藏字段名,默认 wafbi-captcha-response
方法说明
wafbiCaptcha.render(容器, 选项)手动渲染挂件,返回挂件 ID。容器可以是元素或 CSS 选择器
wafbiCaptcha.getResponse(ID)取当前 token,未通过时为空字符串。省略 ID 取第一个挂件
wafbiCaptcha.reset(ID)重置挂件,访客需重新验证。每次提交后调用
wafbiCaptcha.remove(ID)移除挂件

挂件会根据访客浏览器语言显示中文或英文,并跟随系统深浅色。

后端核验

接口说明

请求
POST https://captcha.waf.bi/__captcha/siteverify
Content-Type: application/x-www-form-urlencoded   (也支持 application/json)

secret=sk_你的Secret&response=前端拿到的token&remoteip=访客IP
参数是否必填说明
secret必填密钥的 Secret,只能放在服务端
response必填前端拿到的 token(表单字段 wafbi-captcha-response)
remoteip可选访客 IP,传了会与完成验证的 IP 比对,不一致返回失败
返回
{ "success": true,  "error-codes": [], "hostname": "www.example.com", "challenge_ts": "2026-10-25 14:30:00" }
{ "success": false, "error-codes": ["invalid-input-response"] }

hostname 是嵌入挂件的页面域名,可用来确认 token 来自你自己的网站;challenge_ts 是完成验证的时间(北京时间)。

示例代码

Go
// secret 放在服务端配置里,例如环境变量 WAFBI_CAPTCHA_SECRET
var captchaClient = &http.Client{Timeout: 5 * time.Second}

func verifyCaptcha(ctx context.Context, token, clientIP string) (bool, error) {
	form := url.Values{
		"secret":   {os.Getenv("WAFBI_CAPTCHA_SECRET")},
		"response": {token},
		"remoteip": {clientIP}, // 可选,传了会比对
	}
	req, err := http.NewRequestWithContext(ctx, http.MethodPost,
		"https://captcha.waf.bi/__captcha/siteverify", strings.NewReader(form.Encode()))
	if err != nil {
		return false, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := captchaClient.Do(req)
	if err != nil {
		return false, err
	}
	defer resp.Body.Close()
	var out struct {
		Success bool `json:"success"`
	}
	if err := json.NewDecoder(io.LimitReader(resp.Body, 4096)).Decode(&out); err != nil {
		return false, err
	}
	return out.Success, nil
}

错误码

核验接口返回的 error-codes:

error-codes含义
missing-input-secret没有传 secret
invalid-input-secretsecret 错误、已重置,或密钥已停用、删除
missing-input-response没有传 token
invalid-input-responsetoken 无效、已过期(约 5 分钟)或已经核验过一次
remoteip-mismatch传入的 remoteip 与完成验证的访客 IP 不一致
bad-request请求格式错误

挂件验证失败时 error-callback 收到的错误码:

错误码含义
rate-limited同一 IP 请求过于频繁,稍后再试
blocked访客 IP 已被平台封禁
challenge-expired验证超时或页面停留过久,点击挂件重试
automation-detected检测到自动化浏览器

从 Cloudflare Turnstile 迁移

参数和返回格式与 Turnstile 相同,替换下面几项即可,后端逻辑不用改。

项目Turnstilewaf.bi
脚本地址https://challenges.cloudflare.com/turnstile/v0/api.jshttps://captcha.waf.bi/__captcha/api.js
容器 classcf-turnstilewafbi-captcha
表单字段cf-turnstile-responsewafbi-captcha-response
全局对象turnstilewafbiCaptcha
核验地址https://challenges.cloudflare.com/turnstile/v0/siteverifyhttps://captcha.waf.bi/__captcha/siteverify

注意事项

⚠️
一定要在后端核验,Secret 不能写进前端代码或 App。

token 只能核验一次,约 5 分钟过期,提交后调用 wafbiCaptcha.reset()。核验请求设置 5 秒左右超时。