Go Server SDK
공식 Go 서버 측 SDK입니다 — github.com/Captcha-La/captchala-go.
SDK가 대신 처리해 주는 세 가지 작업:
- Validate — 브라우저 SDK에서 받은
pt_pass token 을 검증합니다. - Issue — 다가올 챌린지를 특정 액션 / IP / UID 에 바인딩하는 일회용
sct_server token 을 발급합니다. - Moderate — 대시보드가 사용하는 동일한 OpenAI 호환 파이프라인을 통한 멀티모달(텍스트 + 이미지) 콘텐츠 모더레이션을 수행합니다.
설치
bash
go get github.com/Captcha-La/captchala-go표준 라이브러리만 사용합니다. 외부 의존성이 없습니다.
Validate (pt_ 토큰)
최종 사용자의 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 timeServer token 발급
가치가 높은 플로우(로그인, 회원가입, 결제)에 권장되는 방식: 백엔드가 일회용 sct_ 토큰을 발급하여 브라우저에 전달하고, 브라우저는 이를 serverToken prop 으로 사용합니다. 단일 사용, 액션 한정이며 선택적으로 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 슬라이스(OpenAI 호환 형식의 텍스트 및/또는 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") {
// 강제 차단
}
}순수 텍스트용 단축 메서드:
go
result, err := client.ModerationText("user comment here", userID)카테고리는 모델이 정의합니다. 고정된 집합을 하드코딩하는 대신 result.Categories 를 방어적으로 순회하십시오.
타입
| Type | Fields |
|---|---|
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) |