部署文档
服务端集成
服务端二次校验集成指南
重要: 服务端二次验证是必需的安全步骤,不可省略!
概述
当用户在前端完成验证后,会生成一组验证参数。您的后端需要将这些参数提交到 Geelab 验证服务进行二次校验,确认验证的有效性。
集成步骤
获取验证参数
从客户端接收以下参数:
| 参数 | 说明 |
|---|---|
lot_number | 验证流水号 |
captcha_output | 验证输出信息 |
pass_token | 验证通过标识 |
gen_time | 验证通过时间戳 |
生成签名
使用 HMAC-SHA256 算法生成 sign_token:
import hmac
import hashlib
sign_token = hmac.new(
CAPTCHA_KEY.encode(),
lot_number.encode(),
hashlib.sha256
).hexdigest()const crypto = require('crypto');
const sign_token = crypto
.createHmac('sha256', CAPTCHA_KEY)
.update(lot_number)
.digest('hex');Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
CAPTCHA_KEY.getBytes("UTF-8"),
"HmacSHA256"
);
mac.init(secretKey);
byte[] hash = mac.doFinal(lot_number.getBytes("UTF-8"));
String sign_token = bytesToHex(hash);$sign_token = hash_hmac('sha256', $lot_number, $CAPTCHA_KEY);h := hmac.New(sha256.New, []byte(CAPTCHA_KEY))
h.Write([]byte(lot_number))
sign_token := hex.EncodeToString(h.Sum(nil))完整的签名生成文档请查看 Server API - 签名生成。
调用验证接口
向 Geelab 验证服务发送 POST 请求。请根据您注册 ID 时选择的地域使用对应的域名:
- 全球:
https://cap-global.geelabapi.com/validate - 欧洲:
https://cap-eu.geelabapi.com/validate - 北美:
https://cap-na.geelabapi.com/validate
POST https://cap-global.geelabapi.com/validate?captcha_id=YOUR_CAPTCHA_ID
Content-Type: application/x-www-form-urlencoded
lot_number=xxx&captcha_output=xxx&pass_token=xxx&gen_time=xxx&sign_token=xxx处理响应
根据响应结果决定是否允许用户操作:
{
"status": "success",
"result": "success",
"reason": ""
}{
"status": "success",
"result": "fail",
"reason": "pass_token expire"
}实现容灾处理
当验证服务异常时,建议放行请求:
try:
response = requests.post(url, data=query, timeout=5)
if response.status_code != 200:
# 接口异常,放行请求
return {'result': 'success', 'reason': 'api error, fallback'}
return response.json()
except Exception as e:
# 请求异常,放行请求
return {'result': 'success', 'reason': 'request fail, fallback'}快速开始
选择您的开发语言查看完整示例:
import hmac
import hashlib
import requests
def validate_captcha(request_data):
# 1. 获取参数
lot_number = request_data.get('lot_number')
captcha_output = request_data.get('captcha_output')
pass_token = request_data.get('pass_token')
gen_time = request_data.get('gen_time')
# 2. 生成签名
sign_token = hmac.new(
CAPTCHA_KEY.encode(),
lot_number.encode(),
hashlib.sha256
).hexdigest()
# 3. 调用验证接口
try:
response = requests.post(
'https://cap-global.geelabapi.com/validate',
params={'captcha_id': CAPTCHA_ID},
data={
'lot_number': lot_number,
'captcha_output': captcha_output,
'pass_token': pass_token,
'gen_time': gen_time,
'sign_token': sign_token
},
timeout=5
)
if response.status_code != 200:
return {'result': 'success', 'reason': 'api error, fallback'}
return response.json()
except Exception as e:
return {'result': 'success', 'reason': 'request fail, fallback'}完整的 Python 实现请查看 Server API 文档。
const crypto = require('crypto');
const axios = require('axios');
async function validateCaptcha(requestData) {
// 1. 获取参数
const { lot_number, captcha_output, pass_token, gen_time } = requestData;
// 2. 生成签名
const sign_token = crypto
.createHmac('sha256', CAPTCHA_KEY)
.update(lot_number)
.digest('hex');
// 3. 调用验证接口
try {
const response = await axios.post(
`https://cap-global.geelabapi.com/validate?captcha_id=${CAPTCHA_ID}`,
new URLSearchParams({
lot_number,
captcha_output,
pass_token,
gen_time,
sign_token
}),
{ timeout: 5000 }
);
if (response.status !== 200) {
return { result: 'success', reason: 'api error, fallback' };
}
return response.data;
} catch (error) {
return { result: 'success', reason: 'request fail, fallback' };
}
}完整的 Node.js 实现请查看 Server API 文档。
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.http.*;
public ValidationResult validate(CaptchaRequest request) {
try {
// 1. 生成签名
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
CAPTCHA_KEY.getBytes("UTF-8"),
"HmacSHA256"
);
mac.init(secretKey);
String signToken = bytesToHex(
mac.doFinal(request.getLotNumber().getBytes("UTF-8"))
);
// 2. 调用验证接口
HttpClient client = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create(API_URL + "?captcha_id=" + CAPTCHA_ID))
.POST(HttpRequest.BodyPublishers.ofString(params))
.timeout(Duration.ofSeconds(5))
.build();
HttpResponse<String> response = client.send(
httpRequest,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
return ValidationResult.fallback();
}
return mapper.readValue(response.body(), ValidationResult.class);
} catch (Exception e) {
return ValidationResult.fallback();
}
}完整的 Java 实现请查看 Server API 文档。
<?php
function validateCaptcha($requestData) {
// 1. 获取参数
$lot_number = $requestData['lot_number'];
$captcha_output = $requestData['captcha_output'];
$pass_token = $requestData['pass_token'];
$gen_time = $requestData['gen_time'];
// 2. 生成签名
$sign_token = hash_hmac('sha256', $lot_number, $CAPTCHA_KEY);
// 3. 调用验证接口
$url = 'https://cap-global.geelabapi.com/validate?captcha_id=' . $CAPTCHA_ID;
$params = http_build_query([
'lot_number' => $lot_number,
'captcha_output' => $captcha_output,
'pass_token' => $pass_token,
'gen_time' => $gen_time,
'sign_token' => $sign_token
]);
try {
$response = @file_get_contents($url, false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => $params,
'timeout' => 5
]
]));
if ($response === false) {
return ['result' => 'success', 'reason' => 'request fail, fallback'];
}
return json_decode($response, true);
} catch (Exception $e) {
return ['result' => 'success', 'reason' => 'exception, fallback'];
}
}
?>完整的 PHP 实现请查看 Server API 文档。
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"net/http"
"net/url"
"strings"
"time"
)
func ValidateCaptcha(requestData map[string]string) (*ValidationResult, error) {
// 1. 获取参数
lotNumber := requestData["lot_number"]
captchaOutput := requestData["captcha_output"]
passToken := requestData["pass_token"]
genTime := requestData["gen_time"]
// 2. 生成签名
h := hmac.New(sha256.New, []byte(CAPTCHA_KEY))
h.Write([]byte(lotNumber))
signToken := hex.EncodeToString(h.Sum(nil))
// 3. 调用验证接口
data := url.Values{}
data.Set("lot_number", lotNumber)
data.Set("captcha_output", captchaOutput)
data.Set("pass_token", passToken)
data.Set("gen_time", genTime)
data.Set("sign_token", signToken)
client := &http.Client{Timeout: 5 * time.Second}
apiURL := API_URL + "?captcha_id=" + CAPTCHA_ID
resp, err := client.Post(
apiURL,
"application/x-www-form-urlencoded",
strings.NewReader(data.Encode()),
)
if err != nil || resp.StatusCode != 200 {
return &ValidationResult{
Result: "success",
Reason: "request fail, fallback",
}, nil
}
defer resp.Body.Close()
var result ValidationResult
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}完整的 Go 实现请查看 Server API 文档。
最佳实践
1. 设置合理的超时时间
建议设置 5 秒超时,避免长时间等待影响用户体验。
2. 实现容灾处理
当验证服务异常时,建议放行请求,避免阻塞业务流程。详细的容灾策略请查看 降级方案。
3. 记录验证日志
记录验证结果和异常情况,便于问题排查:
import logging
logger.info('验证成功', extra={
'lot_number': lot_number,
'result': result['result'],
'user_ip': request.remote_addr
})4. 保护 captcha_key
重要: captcha_key 是敏感信息,必须:
- ✅ 存储在环境变量或密钥管理系统中
- ✅ 不要提交到代码仓库
- ✅ 不要在日志中打印
- ✅ 定期轮换密钥
常见问题
什么情况下返回 pass_token error?
原因: 前后端配置的 ID 不一致。
解决方法:
- 检查前端使用的
captcha_id - 检查后端使用的
captcha_id - 确认两者是否一致
什么情况下报 -50005 错误?
原因: 参数传输格式有误。
检查清单:
-
gen_time是否为纯数字字符串 - Content-Type 是否为
application/x-www-form-urlencoded - 参数是否使用 form data 格式
如何处理验证超时?
建议设置 5 秒超时,超时后放行请求,避免影响用户体验。
相关文档
- Server API 完整文档 - 详细的 API 参数和响应格式
- 降级方案 - 容灾处理和异常处理
- 错误码说明 - 完整的错误码列表
- 常见问题 - 更多问题解答