--- title: Go Server SDK --- # Go Server SDK 官方 Go 伺服器端 SDK — `github.com/Captcha-La/captchala-go`。 SDK 為您處理三項任務: 1. **驗證(Validate)** — 校驗來自瀏覽器 SDK 的 `pt_` pass token。 2. **簽發(Issue)** — 簽發一次性 `sct_` server token,將即將發起的 challenge 綁定到特定 action / IP / UID。 3. **內容審核(Moderate)** — 多模態(文字 + 圖片)內容審核,與控制台共用同一條 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`,請進行比對: ```go if result.UID != expectedUserID { http.Error(w, "user mismatch", http.StatusBadRequest) return } ``` 該次解題的環境資訊也會在 `result.CaptchaArgs` 中回傳,供您參考: ```go ip := result.CaptchaArgs.UserIP // visitor IP recorded at solve time ``` ## 簽發 server token 建議用於高價值流程(登入、註冊、支付):後端簽發一次性 `sct_` token,交給瀏覽器,瀏覽器作為 `serverToken` prop 使用。 單次使用、限定 action,必要時可綁定 IP / UID。 ```go issue, err := client.IssueServerTokenWithOptions("login", captchala.IssueOptions{ BindingIP: userIP, // backend rejects token if a different IP redeems it TTL: 300, // seconds MaxUses: 5, // SDK retry budget BindUID: userID, // pair with ValidateResult.UID on verify }) if err != nil || !issue.OK { http.Error(w, issue.Error, http.StatusBadRequest) return } // hand issue.Token to the browser ``` 僅使用預設值的快捷寫法: ```go issue, err := client.IssueServerToken("login") ``` ## 內容審核 多模態 — 接受 `ModerationItem` 切片(OpenAI 相容格式的 text 與/或 image_url): ```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") { // hard block } } ``` 純文字快捷寫法: ```go result, err := client.ModerationText("user comment here", userID) ``` 分類由模型動態定義;請以遍歷 `result.Categories` 的方式防禦性處理,而非寫死固定集合。 ## 型別 | 型別 | 欄位 | |---|---| | `ValidateResult` | `Valid`、`Error`、`UID`、`ChallengeID`、`Action`、`Offline`、`ClientOnly`、`Warning`、`CaptchaArgs` | | `CaptchaArgs`(資訊性) | `Platform`、`UserIP`、`Referer`、`Pkg`、`SolvedAt`、`RiskScore` | | `IssueResult` | `OK`、`Token`、`ExpiresIn`、`IssuedAt`、`Error`、`Message` | | `IssueOptions` | `BindingIP`、`TTL`、`MaxUses`、`BindUID` | | `ModerationItem` | `Type`、`Text`、`ImageURL`(請使用 `TextItem()` / `ImageURLItem()` 輔助函式) | | `ModerationResult` | `OK`、`Flagged`、`Categories`、`ContentType`、`Raw`、`Error`、`Message`;方法 `HasCategory(...names)` | ## 相關連結 - [pkg.go.dev](https://pkg.go.dev/github.com/Captcha-La/captchala-go) · [GitHub](https://github.com/Captcha-La/captchala-go) - [Web SDK 概覽](/zh-TW/web-sdk) · [API 參考](/zh-TW/api-reference)