Skip to content

Go 服务端 SDK

官方 Go 服务端 SDK —— github.com/Captcha-La/captchala-go

SDK 帮你做三件事:

  1. 校验(Validate)—— 验证浏览器 SDK 返回的 pt_ pass token。
  2. 签发(Issue)—— 签发一次性 sct_ server token, 将本次挑战绑定到具体 action / IP / UID。
  3. 审核(Moderate)—— 多模态(文本 + 图片)内容审核, 走 dashboard 同款 OpenAI 兼容管道。

安装

bash
go get github.com/Captcha-La/captchala-go

只用标准库, 无外部依赖。

校验(pt_ token)

传入终端用户的 IP(从 CF-Connecting-IP / X-Forwarded-For 获取, 回退到 RemoteAddr)。可选,但建议传 —— 用于额外的风控校验。

go
import captchala "github.com/Captcha-La/captchala-go"

client := captchala.NewClient(appKey, appSecret)

func handler(w http.ResponseWriter, r *http.Request) {
    token := r.FormValue("captcha_token")

    result, err := client.ValidateWithClientIP(token, false, clientIP(r))
    if err != nil || !result.Valid {
        http.Error(w, result.Error, http.StatusBadRequest)
        return
    }
    // Verification passed; proceed with the request.
    // result.CaptchaArgs has Platform / UserIP / Referer / Pkg / SolvedAt / RiskScore
}

// Real end-user IP behind a CDN / proxy
func clientIP(r *http.Request) string {
    if ip := r.Header.Get("CF-Connecting-IP"); ip != "" {
        return ip
    }
    if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
        return strings.TrimSpace(strings.Split(xff, ",")[0])
    }
    host, _, _ := net.SplitHostPort(r.RemoteAddr)
    return host
}

手头没有 IP?用 client.Validate(token) —— 校验照常工作, 只是少了基于 IP 的 额外风控信号。

如果原 server_token 带了 bind_uid, 校验时核对 uid:

go
if result.UID != expectedUserID {
    http.Error(w, "user mismatch", http.StatusBadRequest)
    return
}

解题时的上下文也通过 result.CaptchaArgs 返回供参考:

go
ip := result.CaptchaArgs.UserIP   // 解题时记录的访客 IP

签发 server token

注册 / 登录 / 支付等高价值场景推荐流程:后端签发一次性 sct_ token, 下发给前端, 浏览器作为 serverToken 用。单次消费, 绑定 action, 可选绑定 IP / UID。

go
issue, err := client.IssueServerTokenWithOptions("login", captchala.IssueOptions{
    BindingIP: userIP,    // 不同 IP 来兑换会被拒
    TTL:       300,       // 秒
    MaxUses:   5,         // SDK 重试预算
    BindUID:   userID,    // 配合 ValidateResult.UID 校验
})
if err != nil || !issue.OK {
    http.Error(w, issue.Error, http.StatusBadRequest)
    return
}
// 把 issue.Token 下发给浏览器

默认参数快捷方式:

go
issue, err := client.IssueServerToken("login")

内容审核

多模态 —— 接受 ModerationItem 切片(文本 / image_url 混合, OpenAI 兼容):

go
result, err := client.ModerationCheck([]captchala.ModerationItem{
    captchala.TextItem(userComment),
    captchala.ImageURLItem(uploadedImageURL),
}, userID)

if err != nil || !result.OK {
    http.Error(w, result.Error, http.StatusBadRequest)
    return
}

if result.Flagged {
    if result.HasCategory("violence", "csam") {
        // 硬阻断
    }
}

纯文本快捷方式:

go
result, err := client.ModerationText("user comment here", userID)

Category 列表由上游模型决定, 用 result.Categories 防御性遍历, 不要硬编码固定集合。

类型

类型字段
ValidateResultValidErrorUIDChallengeIDActionOfflineClientOnlyWarningCaptchaArgs
CaptchaArgsPlatformUserIPRefererPkgSolvedAtRiskScore(纯信息字段, 切勿基于这些放行)
IssueResultOKTokenExpiresInIssuedAtErrorMessage
IssueOptionsBindingIPTTLMaxUsesBindUID
ModerationItemTypeTextImageURL(用 TextItem() / ImageURLItem() 辅助函数构造)
ModerationResultOKFlaggedCategoriesContentTypeRawErrorMessage;方法 HasCategory(...names)

链接

MIT-licensed examples · CaptchaLa is operated independently