文档中心

自托管行为人机验证 · 六种验证方式 · 弹出式接入 · 云端配置 · 多应用管理 · 开放 API

产品简介

拖动式人机验证:滑块拼图 / 角度旋转 / 曲线重合 / 点击验证 / 文字点选 / 字体选择六种方式,验证图形由服务端生成、答案不出服务端; 配合工作量证明、行为轨迹分析、环境指纹复核与全流程风控,机器脚本难以批量通过。 支持内联与弹窗两种接入形态(弹窗为独立面板,六种方式通用),并检测 WebDriver / 开发者工具等调试环境后立即终止验证。 自托管部署、无第三方依赖、数据完全自有。

快速接入

  1. 控制台创建应用(选择验证方式),得到 app_id / app_secret(secret 只放业务后端)。
  2. 页面引一个入口(apiBase 与 load.js 均使用完整绝对地址;支持跨域接入,服务端 CORS 已放开。接入页与验证服务同域时,域名部分可省略为根绝对路径 /captcha/…):
    <script>window.DinoCaptchaConfig = { apiBase: 'https://你的验证域名/captcha/api/', appId: '你的app_id' };</script>
    <script src="https://你的验证域名/captcha/load.js"></script>
    <div id="box" data-dino-captcha></div>

    加载期间容器自动显示占位条,组件就绪后自动装配。组件所有请求(init / 分段传输 / 拼图 / pow.wasm)都基于 apiBase 解析,不要写相对路径。

  3. 业务后端核验(用户验证通过拿到 token 后,登录等强安全场景建议加 once:true 一次性核验):
    POST https://你的验证域名/captcha/api/open-verify.php
    { "app_id": "…", "app_secret": "…", "token": "…", "once": true }
    // → 200 { code:200, app:"应用名", expires_in:0, consumed:true }

验证方式(控制台按应用选择,随时切换)

方式交互判定
滑块拼图图片碎片乱序 + 缺口滑块位置 ±5px + 行为轨迹 + 环境
角度旋转服务端旋转后的圆形图,拖回正向角度模 360,容差 ±12°
曲线重合滑块平移曲线族,与图中弧线重合顶点位置 ±6px
点击验证单击验证条,WASM POW 直达POW + 环境指纹
点击验证(弹窗)独立面板:上方加载动画 + 下方「验证中…」,完成直接显示验证成功POW + 环境指纹
文字点选按提示顺序点击图中 3 个目标文字坐标 ±22px + 点选节奏
字体选择点击与其它字形样式不同的那个字坐标 ±24px + 节奏

所有方式均叠加:行为轨迹分析、环境指纹复核、全流程风控(频次 / 失败 / 指纹 / 请求头)。

调试环境检测:识别到 WebDriver 自动化标记,或开发者工具(F12 / Ctrl+Shift+I·J·C、面板停靠导致的窗口尺寸差)时, 验证立即终止——清空 token、停止后续请求并提示「检测到调试环境,验证已终止」,失败自动重验同样被禁用; 服务端将 webdriver / devtools 标记作为一票否决项。检测过程不阻塞主线程, iframe 内嵌场景不会误判。

外观(毛玻璃 / 浅色 / 深色)在控制台按应用设置,随资源清单下发、装配时一次成型; 未绑定 appId 的页面可用 DinoCaptchaConfig.theme 指定。

前端:入口与配置

所有配置统一在 load.js 加载:先读 load.js 内置默认值 → 再拉取云端配置(api/client-config.php)→ 最后叠加页面 window.DinoCaptchaConfig。运行中还可调用 DinoCaptcha.configure({…}) 局部更新。

配置项说明
apiBase完整绝对地址(如 https://域名/captcha/api/);缺省取 load.js 所在目录的 api/。支持跨域,组件全部请求基于它解析
appId应用标识(控制台创建);绑定后验证方式与配置以应用为准
mode未绑定 appId 时的展示方式提示(slider / rotate / curve / click / text / font)
theme未绑定 appId 时的外观提示(light / dark / glass);绑定 appId 后以控制台应用配置为准
popup.mode弹出式默认验证方式;留空且未绑定 appId 时自动用 click(单击直达)
popup.title弹窗标题,默认「安全验证」
popup.autoVerify打开弹窗即使用独立面板自动开始(默认 true);设 false 则退回「先显示验证条、点击后再验」
popup.closeDelay / popup.timeout成功后自动关闭延迟(默认 1000ms,留出成功动画时间)/ 弹窗最长存活(默认 300000ms)
cloud设 false 关闭云配置拉取(纯本地配置)

站点自用页面(官网/演示/控制台)通过 api/site-config.php 统一注入绝对 apiBase 与导航链接基准, 站点域名由 config.php 的 site_domain(或环境变量 DINO_SITE_DOMAIN)设置,留空 = 同域根绝对路径。

云端配置

load.js 启动时先 GET /captcha/api/client-config.php(6s 超时,失败静默降级为本地默认值), 取回 { code:200, config:{…} } 合并后继续装配。优先级:load.js 默认值 < 云端配置 < 页面 DinoCaptchaConfig。

// 控制台 API 写入云端配置(全站即时生效,无需改文件)
POST /captcha/api/console.php
{ "action":"setclientcfg", "admin_key":"…",
  "config":{ "mode":"click", "theme":"light",
             "popup":{"title":"请完成安全验证","autoVerify":true,"closeDelay":800} } }

// 清除云端覆盖,回落到 config.php
{ "action":"delclientcfg", "admin_key":"…" }

云端配置只下发白名单字段(mode / theme / appId / title / popup),密钥类字段永不下发。 也可在 config.php 写死 'client_config' => [...],作为云端未配置时的兜底。

三种调用方式,均可读取返回 Promise 的 {pass, token, reason}:

// ① 声明式:load.js 就绪后自动绑定,点击按钮弹窗
<button data-dino-captcha="popup" data-dino-mode="click">安全验证</button>

// ② 一键核验:弹出并立即开始(click 模式直接跑 POW → verify-final)
DinoCaptcha.verify().then(r => { if (r.pass) console.log(r.token); });

// ③ 事件绑定:任意元素 → 弹窗,回调/事件拿到 token
DinoCaptcha.bind('#submit-btn', { mode:'click', title:'请完成安全验证',
    onSuccess: token => {}, onFail: d => {}, onClose: r => {} });

实例与弹窗事件:DinoCaptcha.on('success'|'fail'|'open'|'shrink'|'popup-open'|'popup-close', fn), 同时派发同名 dinocaptcha:* DOM 事件(detail 含 token / pass / reason / container)。

弹窗支持全部六种验证方式

滑块拼图 / 角度旋转 / 曲线重合 / 点击验证 / 文字点选 / 字体选择均可在弹窗中运行, 验证流程与内联组件完全一致(含失败自动重验、重试/关闭按钮、移动端等比缩小)。

弹窗使用独立 UI 面板,不嵌入内联验证条、不显示组件边框,也没有展开/收缩动画: 打开弹窗立即呈现固定尺寸的面板(常规 340×288,文字/字体 340×340)。

弹窗实例不会预先加载挑战:页面加载与点击「登录」之前不产生 init / POW 请求, pow.wasm 与 vendor 依赖也延迟到弹窗首次打开时才加载(纯内联页面则在启动阶段加载); 只有弹窗真正打开后才开始核验。面板内不显示组件自带的关闭控制按钮,统一使用弹窗右上角的 × 关闭。

加载与重试使用统一的 SVG 圆环动画:内联验证条在点击验证进行中显示小号圆环, 弹窗首次加载与面板内「刷新」手动重试显示同款大号圆环 + 状态文案;成功后统一播放「空心圆 + 勾」动画。

验证方式弹窗内的呈现
点击验证整个弹窗就是核验界面:上方 SVG 圆环加载动画 + 下方「验证中…」;完成后同一区域直接播放「空心圆 + 勾」成功动画并显示「验证成功」(失败显示「空心圆 + 叉」与重试提示)
滑块 / 旋转 / 曲线 / 文字 / 字体先显示 SVG 圆环与「验证初始化」,挑战就绪后在同一尺寸面板内直接呈现,无展开过渡;验证通过后显示「验证成功」并播放「空心圆 + 勾」成功动画

设置 autoVerify:false 可退回「先显示验证条、点击后再验证」的传统形态。

方法说明
DinoCaptcha.popup(opts)弹出独立面板并自动开始,返回 Promise;opts 同配置区 popup
DinoCaptcha.verify(opts)同 popup(自动核验),返回 Promise
DinoCaptcha.bind(el, opts)元素点击绑定弹窗;返回 {open, close, on, destroy}
DinoCaptcha.unbind(el)解绑元素
DinoCaptcha.closePopup()关闭当前弹窗(按 reason='api' 结束 Promise)
DinoCaptcha.configure(patch)运行时局部更新配置(深合并)
DinoCaptcha.mount(el)手动挂载内联组件(返回实例)
DinoCaptcha.getToken() / reset()读取当前 token / 触发重新验证
captcha.open / verify / refresh / close / reset / getToken / on / off / destroy实例级便捷方法(window.captcha)

状态变量与事件

window.captcha.container   // 容器名
window.captcha.isPass      // 是否验证成功(true 后可读 token)
window.captcha.token       // 业务 token(验证成功后出现,供后端 open-verify 二次核验;重新验证/失败时清空)
window.captcha.again = true // 触发重新验证(token 同时清空)
window.captcha.open() / verify() / refresh() / close() / reset() / getToken()
                           // 实例便捷方法(内部方法名每代随机,这里用稳定外壳驱动)
window.captcha.on('success'|'fail'|'open'|'shrink', fn)   // 实例事件,返回取消函数
window.IsPass              // 与 captcha.isPass 同步的便捷全局
document.addEventListener('dinocaptcha:ready', …)  // 组件装配完成
document.addEventListener('dinocaptcha:error', …)  // 装载失败(e.detail 为错误对象)
document.addEventListener('dinocaptcha:success', …) // 验证通过(detail.token)
document.addEventListener('dinocaptcha:fail', …)    // 本次验证失败
document.addEventListener('dinocaptcha:popup-open', …) / 'dinocaptcha:popup-close'
                                                    // 弹窗打开 / 关闭(close 含 reason,可为 success/button/mask/escape/timeout/blocked)
document.addEventListener('dinocaptcha:blocked', …) // 检测到调试环境,验证已终止(detail.reason: webdriver/f12/devtools…)

典型取用:前端验证通过后把 captcha.token 随业务表单提交给你的后端,后端调开放 API 核验,token 不得只在前端自证。

开放 API(服务端调用)

POST /captcha/api/open-verify.php · Content-Type: application/json · 仅业务后端调用(app_secret 不进前端)。

请求参数

参数类型必填说明
app_idstring是应用标识(控制台创建)
app_secretstring是应用密钥(仅业务后端持有)
tokenstring是前端验证通过得到的业务 token(captcha.token)
oncebool否是否一次有效:传 true 时校验成功后立即核销 token,同一 token 再次校验返回 404。缺省 false(有效期内可重复校验)。登录、支付、改密等强安全场景建议传 true。

响应(200)

字段说明
code200
app应用名称
created_attoken 签发时间戳(秒)
expires_in剩余有效秒数(token 全生命周期 1 小时);once 核销后为 0
consumedtrue 表示本次校验已核销该 token(once=true 时)

错误码

HTTPcode含义
400400参数缺失(app_id / app_secret / token)
403403应用不存在或已停用;应用密钥错误;token 与应用不匹配
404404token 无效或已过期(含 once 核销后重复校验)
503503存储服务不可用

调用示例

# cURL:一次性核验(推荐登录场景)
curl -s -X POST https://your-domain/captcha/api/open-verify.php \
  -H "Content-Type: application/json" \
  -d '{"app_id":"你的app_id","app_secret":"你的app_secret","token":"前端传来的token","once":true}'
// PHP
$ch = curl_init('https://your-domain/captcha/api/open-verify.php');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'app_id' => $appId, 'app_secret' => $appSecret,
        'token' => $_POST['captcha_token'], 'once' => true,
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$res = json_decode(curl_exec($ch), true);
if ($res['code'] === 200) { // 人机验证通过,继续业务 }
once 使用建议:默认(不传 once)token 在 1 小时内可多次校验,适合"前端验证一次、后端多次确认"的轮询场景; once:true 使 token 首次核验即失效,杜绝 token 重放,适合登录/下单/改密等一次性动作。两种模式按请求选择,同一应用可混用。

控制台 API

POST /captcha/api/console.php · Content-Type: application/json · 除 login 外均需 admin_key(config.php 或环境变量 DINO_ADMIN_KEY;留空则控制台停用,返回 503)。

login(登录,需人机验证)

{ "action": "login", "admin_key": "…", "captcha_token": "前端人机验证 token" }

captcha_token 为控制台页人机验证通过的业务 token,一次性核销:无论密钥对错都消耗,每次尝试都需重新完成人机验证(防密钥爆破)。 返回 200 登录通过;403 未完成人机验证;401 管理密钥错误。

管理动作

action附加参数说明 / 成功响应
list—应用列表(含统计与最近日志)→ {apps:[…]}
createname, domain?, mode?, theme?创建应用 → {app_id, app_secret}(secret 仅此一次展示;theme: light/dark/glass)
setmodeid, mode切换应用验证方式(slider/rotate/curve/click/text/font)
setthemeid, theme切换应用外观(light 浅色 / dark 深色 / glass 毛玻璃),即时生效
getclientcfg—读取 load.js 云配置({config, source})
setclientcfgconfig 或 mode/theme/title/popup写入云端展示配置,全站即时生效(白名单字段,密钥永不下发)
delclientcfg—清除云端覆盖,回落到 config.php
toggleid, enabled启用 / 停用应用
deleteid删除应用(其历史 token 同步失效)
statsid应用统计与最近 50 条验证记录 → {stat_*, logs}

配置参考(config.php)

键默认说明
storagemysqlmysql / redis
mysql.*—连接信息;表自动创建
segment_count3并发传输段数
pow_difficulty5 → 6工作量证明强度区间
verify_modeslider默认验证方式(未绑定应用时)
redis_host / redis_port127.0.0.1 / 6379storage=redis 时的连接
riskenabled风控:qps_per_ip / init_per_min / attempts_10m / fails_10m / fp_per_ip / initonly_gap / whitelist(支持 1.2.3.* 前缀)
prepic_dir / prepic_targetnull / 300AI 素材池目录与目标数量
zhipu_api_key''AI 素材预生成
admin_key''控制台密钥;留空停用
site_domain''站点域名(如 https://cdn.dinonode.org):页面导航与组件 apiBase 生成为绝对地址;留空 = 同域根绝对路径。环境变量 DINO_SITE_DOMAIN 可覆盖
node_bin''node 路径(留空自动探测)
client_config[]云端配置兜底(load.js 拉取 api/client-config.php 时使用;控制台 setclientcfg 优先级更高)

部署

  1. 上传 captcha 目录;PHP ≥7.4 + redis/gd/curl/openssl 扩展;MySQL 建库 captcha。
  2. config.php 填 mysql 连接与 admin_key;npm install(启用深度混淆,可选)。
  3. 按需调整禁用函数(proc_open / popen)或使用计划任务补素材。
  4. Nginx 屏蔽内部目录;自检脚本:php tools/check_env.php。

常见问题