人机验证接入文档商户控制台

客户端配置指南

应用创建后获取对应客户端 Public Key,在业务前端配置展示即可,无需在后台创建主题或逐个添加 login、register 场景。Server Key 只在业务后端使用。

配置优先级

客户端明确传入的参数 → SDK 默认值。服务端 /config 返回的风险规则仍然有效,但 language、product 不再覆盖 SDK 的前端展示参数。Web 自定义 loadConfig() 本身属于前端代码,其展示值可作为默认值,显式顶层参数优先。

scene 是业务动作标识;业务后端核验时使用该接口预期的场景。challengeMode 是题型偏好,服务端可以拒绝或升级;前端必须按返回的 challenge_type 展示实际挑战。

升级时:原先依赖后台 product=invisible 或固定语言的业务,应在初始化参数中明确填写对应 product / language。默认 popup 不会自动启动验证,需点击 SDK 触发器或调用 Web 的 open()。

公开参数

参数 默认值 / 范围 用途
Public Key 必填,各客户端使用自己的凭证 Web captchaId;其余 publicKey
API 地址 按下方各端说明 HTTPS 服务地址,不能混用站点根路径和完整 API 路径
scene 推荐 default,或 login / register 等 前后端必须一致;无需逐个预建
clientType / clientId 对应平台与应用标识 Web/TypeScript 显式传入;原生固定平台;Flutter 自动读取实际包名/Bundle ID
language auto 指定语言或使用运行环境语言;原生自绘 UI 还需绑定本地化资源
product popup;Flutter 弹窗默认 invisible popup 点击触发;float 浮层;bind 绑定业务按钮;invisible 初始化后直接启动,仍可能显示交互挑战
appearance.theme light / dark / auto,默认 light auto 跟随系统明暗主题
appearance.primaryColor #4f6bff,仅 #RRGGBB 主操作颜色;Web/Flutter 自动选择有对比度的按钮文字颜色
appearance.borderRadius 12,整数 0–24 验证外层卡片圆角,单位 CSS px / 逻辑像素;不改变题图坐标
hapticFeedback true 是否允许触觉反馈;无硬件能力时不震动
challengeMode smart smart、slide、click、grid、onetap、rotate、iconcrush、gobang、space、dynamic、voice
请求超时 通常 12 秒,3–30 秒 Web/Flutter/小程序 requestTimeoutMs;Flutter 使用 Duration;Swift timeout 秒;Kotlin timeoutMillis;HarmonyOS timeoutMs;TypeScript request.timeoutMs
配置重试 Web 2;Flutter/小程序 0;范围 0–3 仅配置 GET 的网络/服务错误可重试,挑战创建和提交不能自动重复;原生请求层由调用方重试配置读取

支持语言:zh-CN、zh-TW、en、es、pt-BR、fr、de、ja、ko、ru、ar、hi、id、tr、vi、th、it、nl、pl、uk、fa、he、ms、fil。共享 Web 组件提供这些语言;原生自绘界面须自行提供对应文案。没有浏览器语言环境时建议显式传入设备语言。

以下为 Web 专属交互接口:container(挂载点)、bindTrigger(绑定已有按钮)、open()(手动打开)、reset()(重置)、destroy()(销毁)、onSuccess(取得待核验 Proof)、onState(ready/required/verified/error)、onEvent(生命周期事件)、onError(展示错误)。Flutter 通过 Future<Proof?> 返回成功/取消,onEvent 用于观察生命周期;其他原生和小程序的完成/错误通过 async/Promise 返回,界面事件由业务 UI 管理。

Web 的 enabled、offlineBypass 是兼容参数:只影响本地组件和失败展示,不会生成可信凭证。生产保持 enabled=true、offlineBypass=false,请求失败应允许用户重试。不要用这些开关跳过业务后端核验。

TypeScript 低阶请求支持 headers、fetch、signal、beforeRequest、afterResponse 等扩展;仅在需要自定义传输时使用。小程序支持 request 适配器、sessionId、telemetry。这些客户端数据不应被业务后端直接当作放行依据。

Web / H5

const captcha = RozeCaptcha.init({
  container: '#captcha',
  captchaId: '你的 Web Public Key',
  apiBase: 'https://pink.ya.wang/api/captcha',
  scene: 'login', clientType: 'web', clientId: 'web',
  language: 'zh-CN', product: 'bind', bindTrigger: '#login-button',
  appearance: { theme: 'auto', primaryColor: '#167d50', borderRadius: 8 },
  challengeMode: 'smart', hapticFeedback: true,
  requestTimeoutMs: 12000, configRetries: 2,
  onSuccess: proof => submitLoginToYourBackend(proof),
  onError: error => showError(error.message),
  onEvent: event => recordCaptchaEvent(event),
})
// 页面卸载:captcha.destroy()

一个页面可以挂载多个实例,各自主题互不影响;弹窗 Teleport 到 body 后仍保留自己的配置。题图宽高和拼图位置不可由业务 CSS 单独拉伸,应使用 SDK 的响应式布局。

在 onState 的 ready=true 后调用 open();初始化未完成时应让业务触发按钮保持禁用。题图内容、缺口坐标与旋转中心由服务端挑战决定,不属于前端外观配置。

Flutter Android / iOS

final proof = await PinkCaptcha.verify(context, options: PinkCaptchaOptions(
  publicKey: platformPublicKey,
  apiBase: Uri.parse('https://pink.ya.wang/api/captcha'),
  scene: 'login', language: 'zh-CN', product: 'invisible',
  appearance: PinkCaptchaAppearance(
    theme: 'auto', primaryColor: '#167d50', borderRadius: 8,
  ),
  hapticFeedback: true, configRetries: 1,
  requestTimeout: const Duration(seconds: 12),
  onEvent: (event) => recordCaptchaEvent(event),
));
if (proof != null) await submitToYourBackend(proof.toJson());

Flutter 包内自带交互组件,配置直接生效;不需要业务另写 WebView 页面。product=invisible 避免在已经打开的原生弹窗内再点一次触发按钮。原生标题/错误支持中文和英文,题图内文案使用共享组件语言。

iOS Swift

let options = RozeCaptchaOptions(
    baseURL: URL(string: "https://pink.ya.wang")!,
    publicKey: publicKey, scene: "login", clientId: Bundle.main.bundleIdentifier!,
    language: "zh-CN", product: "popup", hapticFeedback: true,
    appearance: .init(theme: "auto", primaryColor: "#167d50", borderRadius: 8)
)
let client = try RozeCaptchaClient(options: options)
let tokens = options.appearance.viewTokens(darkMode: isSystemDark)
// 原生界面:用 tokens 中的 backgroundColor/textColor/primaryColor/borderRadius 设置自己的视图。
let webOptions = options.webOptions()
// 如已有 WebView 容器:JSONSerialization 编码 webOptions,传给共享 RozeCaptcha.init。

Android Kotlin

val options = RozeCaptchaOptions(
    baseUrl = "https://pink.ya.wang", publicKey = publicKey,
    scene = "login", clientId = context.packageName,
    language = "zh-CN", product = "popup", hapticFeedback = true,
    appearance = RozeCaptchaAppearance("auto", "#167d50", 8),
)
val client = RozeCaptchaClient(options)
val tokens = options.appearance.viewTokens(darkMode = isSystemDark)
// 将 tokens 绑定到自绘界面;或把 options.webOptions() 序列化后交给已有 WebView。

Swift/Kotlin 包提供请求层、配置校验、界面颜色与圆角参数,以及共享 Web SDK 参数映射,不会自动创建原生验证码弹窗。viewTokens() 返回普通数据:业务 UI 需绑定这些值,主题变化时重新计算;hapticFeedback 为 true 时才调用系统震动 API。使用共享 Web 组件则由它应用样式和触觉反馈。

HarmonyOS NEXT

const client = new RozeCaptchaClient({
  baseUrl: 'https://pink.ya.wang', publicKey: publicKey,
  scene: 'login', clientId: bundleName, language: 'zh-CN',
  product: 'popup', hapticFeedback: true,
  appearance: new RozeCaptchaAppearance('auto', '#167d50', 8),
})
const tokens = client.viewTokens(isSystemDark)
const webOptions = client.webOptions()

ArkUI 自绘界面绑定 tokens;已有 ArkWeb 容器可使用 webOptions 初始化共享 Web 组件。SDK 不自动创建 ArkUI 验证弹窗。

微信 / 支付宝 / 抖音小程序

const { createWechatCaptchaClient } = require('./sdk/wechat')
const client = createWechatCaptchaClient({
  baseUrl: 'https://pink.ya.wang/api/captcha', publicKey,
  scene: 'login', clientId: appId, language: 'zh-CN', product: 'popup',
  appearance: { theme: 'auto', primaryColor: '#167d50', borderRadius: 8 },
  challengeMode: 'smart', hapticFeedback: true,
  requestTimeoutMs: 12000, configRetries: 1,
})
this.setData({ captchaPresentation: client.presentation, captchaTokens: client.viewTokens(isSystemDark) })
// 在 WXML/AXML/TTML 中绑定背景色、文字色、圆角和主按钮颜色。
// 产品模式/交互事件由本地组件实现,不能仅设置数据后就认为已渲染验证码。

支付宝换用 createAlipayCaptchaClient,抖音换用 createDouyinCaptchaClient,其他配置相同。传输层不会绘制题图,需使用原生界面完成交互;不能将这些包宣传为内置完整 UI。

TypeScript 自定义界面

import { createCaptchaClient } from './sdk/client-config'
const client = createCaptchaClient({
  baseUrl: 'https://pink.ya.wang', publicKey,
  scene: 'login', clientType: 'web', clientId: 'web',
  language: 'zh-CN', product: 'popup',
  appearance: { theme: 'auto', primaryColor: '#167d50', borderRadius: 8 },
  request: { timeoutMs: 12000, maxAttempts: 2 },
})
// 自绘界面读取 client.presentation。
// 共享 Web UI:RozeCaptcha.init({ container: '#captcha', ...client.webOptions(), onSuccess })
const challenge = await client.createChallenge()

captcha-public.ts 为生成的低阶 API;新代码优先使用 client-config.ts,避免将展示字段放进生成的请求结构。服务端 Node SDK 没有用户界面,不接受主题参数,仍负责消费 Proof 和判断联合验证结果。

必须由服务端处理

前端不能设置放行结果、跳过交互后伪造成功、降低风控阈值、延长凭证寿命或允许重放。只有业务后端核验得到 decision=allow 且 verification=passed 才执行登录/注册等操作。用户取消、网络超时、配置错误都不代表通过。

原生 WebView 接入应加载可信的随包/自托管 Web SDK,使用 JSON 序列化传参,限制页面跳转和消息来源,验证完整 Proof 后再交给业务后端;不要拼接未转义的 HTML/JS 或把 Server Key 放在客户端。