Captcha v4
部署文档

服务端集成

服务端二次校验集成指南

重要: 服务端二次验证是必需的安全步骤,不可省略!

概述

当用户在前端完成验证后,会生成一组验证参数。您的后端需要将这些参数提交到 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'}

快速开始

选择您的开发语言查看完整示例:

Python 快速示例
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 文档

Node.js 快速示例
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 文档

Java 快速示例
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 快速示例
<?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 文档

Go 快速示例
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 不一致。

解决方法:

  1. 检查前端使用的 captcha_id
  2. 检查后端使用的 captcha_id
  3. 确认两者是否一致

什么情况下报 -50005 错误?

原因: 参数传输格式有误。

检查清单:

  • gen_time 是否为纯数字字符串
  • Content-Type 是否为 application/x-www-form-urlencoded
  • 参数是否使用 form data 格式

如何处理验证超时?

建议设置 5 秒超时,超时后放行请求,避免影响用户体验。

相关文档