{"openapi":"3.0.3","info":{"title":"点击验证码","description":"点击图形完成人机验证的验证码组件。\n## 接入指南\n\n在网页中引入 JS 组件完成人机验证：验证成功后 token 自动写入表单隐藏字段随表单提交，你的后端取出 token 调用 `verify` 完成最终校验（防止前端伪造验证结果）。captcha / click 由组件内部自动调用，无需自行对接。\n\n### 第 1 步 · 引入 JS 文件\n\n在页面 `<head>` 或 `</body>` 前引入（组件所需 CSS 会自动注入，无需手动引入）：\n\n```html\n<script src=\"https://api.physton.com/api/pcaptcha/data/js/pcaptcha.min.js\"></script>\n```\n\n### 第 2 步 · 放置容器并初始化\n\n方式一：JS 初始化（可监听验证结果回调）：\n\n```html\n<div id=\"captcha-box\"></div>\n<script>\n    Pcaptcha.init(document.getElementById('captcha-box'), {\n        appid: '你的AppID',\n        // theme: 'theme-default',    // theme-default | theme-dark | theme-light | theme-transparent\n        // input_name: 'pcaptcha',    // token 写入的隐藏 input 名称\n        onsuccess: function (instance) {\n            // 验证成功：instance.token 即验证凭据\n        },\n        onfail: function (instance, data) {\n            // 验证失败：可点击组件重试\n        }\n    });\n</script>\n```\n\n方式二：声明式（DOM 就绪后自动初始化）：\n\n```html\n<div data-pcaptcha data-appid=\"你的AppID\"></div>\n```\n\n配置项：\n\n| 配置项 | 类型 | 说明 | 默认值 |\n| --- | --- | --- | --- |\n| appid | string | 必填。AppID：需已授权 pcaptcha 插件，且接入页域名在该应用的来源域名白名单内 | — |\n| theme | string | 组件主题：theme-default / theme-dark / theme-light / theme-transparent | theme-default |\n| width | string | 组件宽度（任意 CSS 宽度值） | 100% |\n| input_name | string | 验证成功后 token 写入的隐藏 input 名称 | pcaptcha |\n| onload | function | 组件初始化完成回调 function (instance) | — |\n| onsuccess | function | 验证成功回调 function (instance) | — |\n| onfail | function | 验证失败回调 function (instance, data) | — |\n\n重置组件（验证成功后需重新验证时调用）：`Pcaptcha.reset(el)`，el 为容器元素或其选择器。\n\n### 第 3 步 · 后端调用 verify 完成最终校验\n\n验证成功后组件会在容器内生成隐藏 input（name 默认 `pcaptcha`，可用 `input_name` 配置），token 随表单一并提交到你的后端：\n\n```html\n<form method=\"post\" action=\"/login\">\n    <div data-pcaptcha data-appid=\"你的AppID\"></div>\n    <!-- 验证成功后组件自动生成：<input type=\"hidden\" name=\"pcaptcha\" value=\"token\" /> -->\n    <button type=\"submit\">提交</button>\n</form>\n```\n\n你的后端收到 token 后，携带 `X-App-Id` / `X-App-Secret`（或 HMAC 签名，见文档页右上角「鉴权助手」）调用：\n\n```http\nPOST https://api.physton.com/api/pcaptcha/verify\nContent-Type: application/x-www-form-urlencoded\n\ntoken=用户提交的token\n```\n\n返回 `code=200` 即验证通过。注意：token 为一次性凭据，verify 通过即刻销毁，请勿对同一 token 重试。接口详细参数见下方文档。\n### 平台统一约定\n- **响应信封**：`output=json`（默认）返回 `{code, msg, data}`，code 与 HTTP 状态码一致；`output=raw` 直接返回简单文本或图片二进制\n- **鉴权**：公开接口无需凭据；需鉴权接口携带 `X-App-Id` + `X-App-Secret`（明文）或 `X-App-Id` + `X-Timestamp` + `X-Nonce` + `X-Signature`（HMAC-SHA256 签名），文档页右上角「鉴权助手」可在线生成请求头\n- **默认限流**：60 次/秒，1000 次/时，3000 次/天（粒度 {appid|ip}:{plugin}，appid 级配额可覆盖；超限返回 429）\n- **文档数据**：接口参数/返回/示例来自 handler 方法 PHPDoc 注解，方法注册/鉴权/限流来自 manifest","version":"1.0.0"},"servers":[{"url":"/api/pcaptcha","description":"当前站点"}],"tags":[{"name":"公开接口","description":"无需凭据即可调用"},{"name":"需鉴权接口","description":"需携带 appid/appsecret（明文双头或 HMAC 签名），详见「鉴权助手」"}],"paths":{"/verify":{"post":{"tags":["需鉴权接口"],"summary":"后端最终校验（需鉴权）","description":"由使用方后端调用（携带 appid/appsecret 凭据，避免 appsecret 暴露给前端），\n校验 click 通过后的 token 是否有效，防止前端伪造校验结果。\n严格绑定：鉴权 appid 必须与获取验证码时的 appid 一致；严格一次性：通过即销毁 token，\n重复 verify 同一 token 将失败（请勿在业务侧做 verify 超时重试）。\n\n**返回**：验证通过 data 为空、msg 为提示；失败返回 400（无效/不匹配/已使用）/401（凭据无效）\n\n**默认限流**：60 次/秒，1000 次/时，3000 次/天（appid 级配额可覆盖）","operationId":"pcaptcha_verify","x-auth-required":true,"x-rate-limit":{"s":60,"h":1000,"d":3000},"parameters":[{"name":"output","in":"query","required":false,"description":"json（默认，统一信封）|raw（纯文本）","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"click 验证成功后的 token"}},"required":["token"]}}}},"responses":{"200":{"description":"成功","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"},"example":{"code":200,"msg":"验证通过","data":[]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"400":{"$ref":"#/components/responses/BadRequest"}},"security":[{"plainAppId":[],"plainSecret":[]},{"hmacAppId":[],"hmacTimestamp":[],"hmacNonce":[],"hmacSignature":[]}]}}},"components":{"schemas":{"Envelope":{"type":"object","description":"平台统一响应信封，code 与 HTTP 状态码一致；output=raw 时无信封（直接输出文本/图片二进制）","properties":{"code":{"type":"integer","description":"200 成功；400 参数错误；401 凭据无效；403 拒绝访问；429 触发限流；500 服务异常"},"msg":{"type":"string","description":"提示信息"},"data":{"type":"object","description":"业务数据（结构见各接口说明）"}}}},"securitySchemes":{"plainAppId":{"type":"apiKey","in":"header","name":"X-App-Id","description":"明文方式：appid"},"plainSecret":{"type":"apiKey","in":"header","name":"X-App-Secret","description":"明文方式：appsecret（HTTPS 下使用）"},"hmacAppId":{"type":"apiKey","in":"header","name":"X-App-Id","description":"HMAC 方式：appid"},"hmacTimestamp":{"type":"apiKey","in":"header","name":"X-Timestamp","description":"HMAC 方式：秒级时间戳（±300s 时间窗）"},"hmacNonce":{"type":"apiKey","in":"header","name":"X-Nonce","description":"HMAC 方式：一次性随机串（5 分钟内不可重复）"},"hmacSignature":{"type":"apiKey","in":"header","name":"X-Signature","description":"HMAC 方式：base64(HMAC-SHA256(secret, 签名串))，签名串见「鉴权助手」"}},"responses":{"BadRequest":{"description":"参数错误（缺少必填/格式非法）","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"Unauthorized":{"description":"凭据缺失或无效（appid 不存在/停用/未授权该插件/签名错误）","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"Forbidden":{"description":"拒绝访问（IP/UA 名单命中）","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"RateLimited":{"description":"触发限流（X-RateLimit-Remaining: 0，Retry-After 头提示等待秒数）","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"ServerError":{"description":"服务端异常","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}}}},"x-plugin":{"slug":"pcaptcha","name":"点击验证码","description":"点击图形完成人机验证的验证码组件。","version":"1.0.0","methodCount":3,"authMethods":["verify"],"rateLimit":{"s":60,"h":1000,"d":3000},"warnings":[]}}