接入人机验证 BitCaptcha
对应 SDK 0.6.2 · 更新于 2026-09-15
人机验证 BitCaptcha 是星辉数盾的人机验证服务:前端拿一次性凭证,后端核销放行。四端一份 SDK,几分钟接上。
快速接入
三步接上一个登录 / 注册 / 下单的人机验证。
- 1在 控制台注册,拿到站点的
captcha_id(客户端用)与secret_key(只放后端)。 - 2前端引入 SDK,用户通过后在
onVerify拿到validate,随业务请求提交。 - 3后端带
secret_key调核销接口,result:true才放行。
<div id="captcha"></div> <script src="https://shudun.bitbeam.cn/sdk/bitcaptcha.min.js"></script> <script> BitCaptcha.init({ element: '#captcha', captchaId: 'YOUR_CAPTCHA_ID', onVerify(err, data) { // data.validate 交给后端核销 if (!err) submitLogin({ captcha: data.validate }) } }) </script>
工作原理与凭证模型
三个角色:客户端(网页 / 小程序 / App)展示拼图并拿到一次性凭证 validate;你的业务后端带 secret_key 核销凭证;星辉数盾服务出题、判定、签发凭证。
| 名词 | 放在哪 | 说明 |
|---|---|---|
captcha_id | 客户端 | 站点标识,24 位十六进制。泄露无害,配合 Origin 白名单可防盗用。 |
secret_key | 仅业务后端 | 核销凭证用,48 位十六进制。可在控制台轮换,轮换后旧 key 立即失效。 |
validate | 客户端 → 业务后端 | 一次性通过凭证(带签名与过期时间),约 120 字符。 |
token | SDK 内部 | 一道题的标识,2 分钟过期,只能校验一次,业务侧无需关心。 |
服务端二次校验
这一步必须做,而且只能在你的服务器上做。只有核销成功才放行业务。
curl -X POST https://shudun.bitbeam.cn/api/v1/captcha/verify \ -H 'Content-Type: application/json' \ -d '{"validate": "前端提交的 validate", "secret_key": "你的 secret_key"}'
r = requests.post(f"{HOST}/api/v1/captcha/verify",
json={"validate": validate, "secret_key": SECRET}, timeout=5)
if not r.json().get("result"):
abort(400, "captcha failed")
const r = await fetch(`${HOST}/api/v1/captcha/verify`, {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ validate, secret_key: process.env.CAPTCHA_SECRET })
}).then(r => r.json());
if (!r.result) throw new Error("captcha failed");
| 返回字段 | 类型 | 说明 |
|---|---|---|
result | boolean | true 放行;false 拒绝 |
captcha_id | string | 核销的站点 id,建议与你配置的比对 |
token | string | 本题标识,用于日志关联 |
reason | string | used 已核销 · expired 超 180s · bad_signature 被篡改或 secret 已轮换 · bad_secret secret 不对 · malformed 格式错误 |
validate 只能核销一次,重放会得到 used;接口超时(建议 5s)按拒绝处理并提示重试。安全与数据
- 答案只在服务端;客户端拿到的是题图和运动方式。位置与角度必须同时对上,每题曲线不同。
- 一道题只能校验一次,2 分钟过期;凭证只能核销一次,180 秒过期。
- 服务端综合拖动轨迹、时序、运行环境等信号打分,并对同一来源的连续失败做冷却。
- 智能无感知按风险分级:多数真人无感通过,可疑流量自动升级为图形验证而非直接拒绝,兼顾安全与转化。可疑来源会被转入"严格"一段时间(一律图形验证);站点也可在控制台直接设为严格模式——登录、注册、领券这类高价值动作建议选它。
- 校验请求的载荷在客户端加密传输,配合 SDK 版本轮换抬高脚本伪造成本。
- Origin 白名单可防止其他网站盗用你的 captcha_id 消耗额度。
- 只加载图片不验证的刷图流量会被自动识别并临时限制,不消耗你的额度;控制台会提示,误判可联系我们解除。
采集了什么
为区分人和机器,SDK 在拖动时上报:滑块位移与轨迹(相对坐标与时间)、屏幕尺寸与像素比、语言与时区、是否触屏、是否处于自动化环境。服务端记录请求 IP 与 UA 摘要用于绑定与限流,保留不超过 10 分钟。不采集 Cookie、账号、页面内容或输入框内容。以上口径可直接写入隐私政策。
额度与账单
按验证次数计费:用户提交答案一次、或智能无感知直接通过一次,各算一次;验证码加载与换题不计。额度属于账号,名下所有站点共用。
- 每月 10,000 次免费额度,按 UTC 自然月、每月 1 日重置;控制台「概览」有本月用量与进度,「用量」页可查按月账单。
- 免费额度用完后自动从次数包扣,按到期先后扣;次数包在控制台「充值」页购买(支付宝),12 个月有效,支付成功立即到账、不影响已有余额。
- 免费额度用完且没有余额时,取题接口返回
429(detail: quota_exceeded),验证码显示"加载失败",充值或下月重置后自动恢复;控制台会提前提示。 - 企业客户、发票、对公转账或不限量方案请联系我们,后台入账即时生效。
私有化部署
git clone ... shudun && cd shudun # 改 docker-compose.yml 里的 SESSION_SECRET / PUBLIC_URL docker compose up -d --build curl -s http://127.0.0.1:8790/api/v1/health # {"status":"ok"}
| 环境变量 | 默认 | 说明 |
|---|---|---|
BITCAPTCHA_PUBLIC_URL | 按请求推断 | 对外地址:控制台 / 文档 / 产品页里的接入代码与 llms.txt 里的域名都从这里来 |
BITCAPTCHA_SESSION_SECRET | 随机 | 控制台登录态签名(固定一个值;登录态闲置 30 天失效,活跃自动续期),生产必填,否则重启即登出 |
BITCAPTCHA_SDK_KEY | bitcaptcha-sdk-v1 | 与三端 SDK 内置值一致,改动需同时发新版 SDK |
BITCAPTCHA_DATABASE_URL | 必填 | PostgreSQL 连接串;compose 自带一个,也可指向云数据库 |
BITCAPTCHA_REDIS_URL | 空(进程内) | 多实例 / 多 worker 必填 |
BITCAPTCHA_TRUST_PROXY | 0 | nginx 之后置 1,否则限流按代理 IP 算 |
BITCAPTCHA_ALLOW_REGISTER | 1 | 私有部署建好账号后可关闭注册 |
BITBEAM_ADMIN_EMAILS | 空 | 超级管理员邮箱名单(逗号分隔),可进 /admin 平台后台 |
BITBEAM_LLM_KEY | 空 | 文档「问 AI」的模型服务密钥(环境变量只作缺省;后台「平台配置」可改,开关默认关闭) |
BITBEAM_FREE_QUOTA | 10000 | 每账号每月验证次数默认额度,0 为不限;后台可按账号覆盖 |
BITBEAM_ALERT_WEBHOOK | 空 | 告警群机器人地址(飞书 / 钉钉 / 企业微信自动识别);后台「平台配置」可改,以后台为准 |
BITBEAM_METRICS_TOKEN | 空 | 开启 /api/v1/metrics(Prometheus 格式)的访问 token,空则关闭 |
BITBEAM_ALIPAY_APP_ID / PRIVATE_KEY / PUBLIC_KEY | 空 | 支付宝电脑网站支付:应用 ID、应用私钥、支付宝公钥;三者齐了控制台才开放自助购买 |
BITBEAM_ALIPAY_GATEWAY | 正式网关 | 联调时换成沙箱网关 |
BITBEAM_PACKS | 空 | JSON 数组整体替换次数包目录(名称 / 次数 / 价格 / 有效期) |
BITBEAM_SIGNUP_CREDITS | 0 | 注册赠送的一次性次数(12 个月有效);想改成"一共送 1 万"就设它并把 FREE_QUOTA 置 0 |
BITCAPTCHA_TOLERANCE / RISK_THRESHOLD | 5 / 0.6 | 拼图容差(px)/ 行为风险阈值 |
完整变量见 server/.env.example。
探活与监控
GET /api/v1/health 会实际检查数据库与 Redis,任一异常返回 503,可直接接云监控或 UptimeRobot 探活;进程内每分钟也自检一次,依赖故障与恢复、未捕获异常、错误激增、商户额度到 80% / 100% 都会推到告警群。配置 BITBEAM_METRICS_TOKEN 后,GET /api/v1/metrics(Authorization: Bearer <token>)输出 Prometheus 指标:请求量与时延、取题 / 校验 / 通过、拦截与冷却、数据库连接池。
Web / H5 SDK
无依赖,一个 <script> 引入,兼容现代浏览器与移动端 WebView(需 https,localhost 除外)。样式由 SDK 自动加载。
sense 智能无感知(点一下即过,可疑流量自动升级为图形验证)、slider 增强版滑动拼图(默认)、textclick 文字点选(enhanced:true 文字带旋转更防破解)、iconclick 图标点选。无论哪种,通过后都拿到一次性 validate,业务后端二次核销才算数。宽度默认自适应铺满容器并在 minWidth–maxWidth(280–400)间收敛;要固定宽传数字 width:320。初始化参数
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
element | string | Element | 必填 | 容器选择器或元素 |
captchaId | string | 必填 | 控制台里的 captcha_id |
type | string | 'slider' | sense 智能无感知 / slider 滑动拼图 / textclick 文字点选 / iconclick 图标点选 |
enhanced | boolean | true | 仅文字点选:true 旋转 / false 正放 |
mode | string | 'embed' | embed 嵌入 / popup 弹出 / float 触发 |
width | number | string | '100%' | 默认自适应;传数字则固定 px |
theme / lang | string | light / auto | 主题与语言,见多语言与主题 |
maxErrors | number | 5 | 连续失败几次后停止自动换题,改为点击刷新 |
lazy | boolean | true | 嵌入 / 触发式滚进视口附近才取题;首屏之外的验证码不提前加载。三端同名 |
onReady / onVerify / onError / onClose | function | - | 就绪 / 校验结果 / 错误 / 弹窗关闭 |
回调 onVerify(err, data)
| 字段 | 说明 |
|---|---|
err | 通过为 null;失败时 err.code 为错误码,SDK 会 1s 后自动换题。连续失败达到 maxErrors 改为"点击刷新";若某次失败触发了来源冷却,err.retryAfter 给出秒数,控件直接进入倒计时、到点自动重新取题 |
data.validate | 一次性通过凭证,提交给后端核销 |
data.token / data.captchaId | 本题标识 / 站点 id |
实例方法
refresh() | 换一题 |
popUp() / close() | 弹出式:手动打开 / 关闭 |
getValidate() | 取最近一次通过的 validate |
reset() | 清掉通过状态并换题(业务提交失败后重新验证) |
destroy() | 移除组件与事件 |
微信小程序
下载组件包,解压后把 bitcaptcha 目录放到小程序 components/ 下;后台"开发设置 → request 合法域名"加入接口域名。拖动在视图层(WXS)处理,跟手不卡顿。
<!-- page.json --> { "usingComponents": { "bitcaptcha": "/components/bitcaptcha/index" } } <!-- page.wxml --> <bitcaptcha captcha-id="YOUR_CAPTCHA_ID" api-base="https://shudun.bitbeam.cn" mode="embed" bind:verify="onVerify" /> <!-- 智能无感知:点一下,安全用户直接过,可疑自动切成拼图 --> <bitcaptcha captcha-id="YOUR_CAPTCHA_ID" api-base="https://shudun.bitbeam.cn" type="sense" bind:verify="onVerify" /> // page.js Page({ onVerify(e) { const { validate } = e.detail wx.request({ url: '/login', method: 'POST', data: { captcha: validate } }) } })
| 属性 | 默认 | 说明 |
|---|---|---|
captcha-id / api-base | 必填 | 站点 id / 接口地址(https) |
type / enhanced | slider / true | 同 Web,enhanced="{{false}}" 为普通版 |
mode | embed | embed / popup(小程序无 hover,不提供 float) |
width | '100%' | 自适应;width="{{320}}" 固定 px |
lazy | true | 滚进视口附近才取题 / 准备无感知;lazy="{{false}}" 立刻 |
bind:verify / bind:error | - | e.detail = { validate, token, captchaId } / { code } |
Flutter
包已发布到 pub.dev,支持 iOS / Android / Web / 桌面。
dependencies: bitcaptcha_flutter: ^0.6.2
import 'package:bitcaptcha_flutter/bitcaptcha_flutter.dart'; // 嵌入式 BitCaptcha( captchaId: 'YOUR_CAPTCHA_ID', apiBase: 'https://shudun.bitbeam.cn', onVerify: (r) => login(captcha: r.validate), ) // 弹窗式:用户关闭返回 null final r = await showBitCaptcha(context, captchaId: 'YOUR_CAPTCHA_ID', apiBase: 'https://shudun.bitbeam.cn'); if (r != null) login(captcha: r.validate); // 文字点选:BitCaptchaText / showBitCaptchaText(enhanced: bool) // 智能无感知:点一下,安全用户直接过,可疑自动弹出拼图 BitCaptchaSense( captchaId: 'YOUR_CAPTCHA_ID', apiBase: 'https://shudun.bitbeam.cn', onVerify: (r) => login(captcha: r.validate), )
| 参数 | 默认 | 说明 |
|---|---|---|
captchaId / apiBase | 必填 | 站点 id / 接口地址 |
onVerify | 必填 | r.validate r.token r.captchaId |
fluid / width | true / 320 | 默认铺满父容器;fluid:false 用固定 width |
theme / lang / maxErrors | light / auto / 5 | 同 Web,const BitCaptchaTheme.dark() 或自定义色 |
lazy | true | 滚进视口附近才取题 / 准备无感知(三端同名);不在滚动容器里立即生效 |
错误码
客户端 onVerify 的 err.code(小程序 bind:error 的 detail.code)。都由 SDK 自动处理,列出便于埋点。
| code | 含义 | SDK 行为 |
|---|---|---|
mismatch | 没拼到位 | 提示"验证失败",1s 后换题 |
behavior | 轨迹或环境判定为机器 | 提示"操作异常",1s 后换题 |
token_expired | 题目超 2 分钟或已校验过 | 提示过期,换题 |
token_mismatch | 取题与校验不是同一客户端 | 换题 |
bad_payload | 载荷无法解密(SDK 与服务端版本不一致) | 换题;持续出现请升级 SDK |
加载失败的分类
取题 / 无感知请求失败时走 onError(小程序 bind:error,Flutter onError 收到 BitCaptchaException),错误对象带 code;三端把原因分开告诉用户,不会一句"加载失败"让用户以为你的站点坏了。
| code | 含义 | 用户看到 |
|---|---|---|
rate_limited / cooldown | 请求过于频繁,或短时间内失败过多进入冷却;响应带 Retry-After(秒),错误对象里是 retryAfter | "操作太频繁,N 秒后自动重试",倒计时期间点击无效,到点自动重新取题 |
network | 请求没到服务端(断网 / 超时 / 图片没下下来) | "网络不给力,点击重试" |
server | 服务端 5xx | "服务开小差了,点击重试" |
quota_exceeded | 账号本月额度用完且没有余额 | "加载失败,点击重试"(额度是商户侧的事,不向终端用户解释;控制台会提前提示) |
http | 其它 4xx:400 未知 captcha_id · 403 来源不在 Origin 白名单 / 账号已停用 | "加载失败,点击重试";接入时看 err.status / err.detail 排查 |
多语言与主题
内置 zh-CN zh-TW en ja ko,lang:'auto' 按浏览器 / 系统语言归并。三端键名一致,可用 i18n 逐条覆盖。
BitCaptcha.init({ ..., lang: 'en',
i18n: { slide: 'Drag to verify', success: 'Welcome back' } })
主题
Web 端除 theme:'dark' 外,可在容器上覆盖 CSS 变量;Flutter 用 BitCaptchaTheme(primary: ..., success: ...)。
#captcha .bc { --bc-primary: #7c3aed; --bc-primary-soft: #ede9fe; }
AI 接入(MCP 与 llms.txt)
星辉数盾面向 AI 编程助手与 Agent 提供两种接入方式,让"接入人机验证"这件事对 AI 也友好。
llms.txt
遵循 llms.txt 约定,站点根目录提供两份纯文本文档:
/llms.txt | 精简索引,含核心模型与各页链接 |
/llms-full.txt | 全文 Markdown,可整份喂给 LLM |
页面右上角"复制页面"可一键复制为 Markdown,或"在 ChatGPT / Claude 打开"直接带上文档提问。
MCP server
一个只读的 MCP 服务,暴露工具给 Claude Desktop、Cursor 等 AI 客户端调用,让它们在帮你写接入代码时能查文档、取片段、看服务状态。
| 工具 | 作用 |
|---|---|
search_docs(query) | 在文档里检索,返回相关章节 |
get_snippet(platform, type) | 返回某端(web/mp/flutter/server)的接入代码 |
service_health() | 查询服务健康 |
{
"mcpServers": {
"shudun": {
"command": "python",
"args": ["integrations/mcp-server/server.py"],
"env": { "BITBEAM_HOST": "https://shudun.bitbeam.cn" }
}
}
}
integrations/mcp-server/;依赖 pip install mcp httpx。Cursor 等客户端配置方式类似。