极验(GeeTest)GT4 是国内主流第三方行为验证服务,提供滑块、点选、一键通过等验证形态。本文详解 GT4 的前后端完整接入流程、三种展示模式的差异、服务端二次校验闭环,以及第三方验证服务的容灾设计思路。
核心原则:只做前端集成、不做服务端二次校验,安全上等于没接完整。
<script src="https://static.geetest.com/v4/gt4.js"></script>
<div id="captcha-box"></div>
<script>
initGeetest4(
{
captchaId: "你的-captchaId",
product: "popup",
language: "zho",
protocol: "https://",
},
function (captchaObj) {
captchaObj.appendTo("#captcha-box");
}
);
</script>关键参数:
| 参数 | 说明 | 注意事项 |
|---|---|---|
| captchaId | 极验后台申请的产品 ID | 必填,非本地自定义 |
| product | 展示模式:popup/bind/float | 影响触发方式 |
| language | 界面语言 | zho 为中文 |
| protocol | 协议头 | 本地调试时特别注意 |
| 模式 | 触发方式 | 特点 |
|---|---|---|
| popup | 自动弹出 | 体验最均衡,推荐默认选择 |
| bind | 需主动调用 showCaptcha() | 绑定按钮触发 |
| float | 按钮附近浮层 | 需关注容器布局 |
bind 模式示例:
initGeetest4(
{ captchaId: "你的-captchaId", product: "bind" },
function (captchaObj) {
const btn = document.getElementById("verify-btn");
captchaObj.onReady(function () {
btn.disabled = false;
});
btn.addEventListener("click", function () {
captchaObj.showCaptcha();
});
}
);let captchaInstance = null;
initGeetest4(
{ captchaId: "你的-captchaId", product: "popup" },
function (captchaObj) {
captchaInstance = captchaObj;
captchaObj
.appendTo("#captcha-box")
.onSuccess(async function () {
const result = captchaObj.getValidate();
if (!result) return;
await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: "demo",
password: "123456",
captchaResult: result,
}),
});
});
}
);要点:
getValidate() 应在 onSuccess 回调中调用reset() 让用户重新验证import express from "express";
import crypto from "crypto";
const app = express();
app.use(express.json());
app.post("/api/login", async (req, res) => {
const { username, password, captchaResult } = req.body;
if (!captchaResult) {
return res.status(400).json({ message: "缺少验证码校验结果" });
}
// 构造签名(具体以极验服务端文档为准)
const signToken = crypto
.createHash("sha256")
.update("demo")
.digest("hex");
const verifyResponse = await fetch(
"https://gcaptcha4.geetest.com/validate",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sign_token: signToken,
lot_number: captchaResult.lot_number,
captcha_output: captchaResult.captcha_output,
pass_token: captchaResult.pass_token,
gen_time: captchaResult.gen_time,
}),
}
);
const verifyResult = await verifyResponse.json();
if (verifyResult.result !== "success") {
return res.status(403).json({ message: "极验校验未通过" });
}
// 极验通过后才执行业务逻辑
if (username === "admin" && password === "123456") {
return res.json({ message: "登录成功" });
}
return res.status(401).json({ message: "账号或密码错误" });
});第三方服务一旦异常,可能阻塞登录、注册、短信发送等主业务链路。如果代码把"校验失败"直接等同于"业务拒绝",第三方不可达时业务整体瘫痪。
validate 请求异常async function verifyGeetestOrBypass(payload: Record<string, string>) {
try {
const response = await fetch(
"https://gcaptcha4.geetest.com/validate",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
}
);
if (!response.ok) {
throw new Error(`validate status: ${response.status}`);
}
return await response.json();
} catch (error) {
// 容灾放行(业务决策,非安全最优解)
return {
result: "success",
reason: "request geetest api fail",
bypass: true,
};
}
}| 场景 | 容灾策略 | 理由 |
|---|---|---|
| 登录 | 可适度放行 | 还有密码校验兜底 |
| 短信发送 | 谨慎/拒绝 | 有直接经济成本 |
| 支付确认 | 不放行 | 资金安全优先 |
| 营销活动 | 可适度放行 | 避免影响正常参与 |
极验主域名与备用域名:
gcaptcha4.geetest.com、static.geetest.comgcaptcha4.geevisit.com、gcaptcha4.gsensebot.com公司内网或安全代理环境需提前放行。
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 前端验证通过但业务请求没发出 | 接口地址缺少 http:// 或 https:// | 先查 Console 和 Network,区分验证链路和业务请求 |
| 初始化成功但验证框不显示 | bind 模式未调用 showCaptcha() | 根据模式选择正确触发方式 |
| 前端拿不到校验结果 | 未在 onSuccess 中调用 getValidate() | 在成功回调里读取 |
| 服务端一直校验失败 | 字段不完整/签名错误 | 对照官方文档检查参数 |
| 第三方异常导致登录不可用 | 无容灾降级 | 对 validate 请求做 try/catch + 分级放行 |
| 内网无法访问极验 | 域名未放行 | 提前验证网络并放行官方域名 |