Go SDK
提供 A7Client 参考实现,仅依赖标准库(crypto/md5、crypto/rc4、net/http、encoding/hex、net/url、encoding/json)。
完整参考实现
a7client.go:
go
package a7verify
import (
"bytes"
"crypto/md5"
"crypto/rc4"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strconv"
"time"
)
const baseURL = "https://api.a7p.cn/api/verify"
type A7Client struct {
AppID string
AppKey string
ApiPassword string
http *http.Client
}
func New(appID, appKey string) *A7Client {
return &A7Client{AppID: appID, AppKey: appKey, http: &http.Client{Timeout: 15 * time.Second}}
}
func md5hex(s string) string {
h := md5.Sum([]byte(s))
return hex.EncodeToString(h[:])
}
// rc4Hex 返回 RC4 密文的十六进制(大写)
func rc4Hex(key, plain string) (string, error) {
c, err := rc4.NewCipher([]byte(key))
if err != nil {
return "", err
}
src := []byte(plain)
dst := make([]byte, len(src))
c.XORKeyStream(dst, src)
return hex.EncodeToString(dst), nil // 转大写
}
func (c *A7Client) post(fields url.Values, headers map[string]string) (map[string]any, error) {
req, err := http.NewRequest(http.MethodPost, baseURL, bytes.NewBufferString(fields.Encode()))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
for k, v := range headers {
req.Header.Set(k, v)
}
resp, err := c.http.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var out map[string]any
if err := json.Unmarshal(body, &out); err != nil {
return nil, err
}
return out, nil
}
// Init 握手获取 ApiPassword
func (c *A7Client) Init() error {
ts := strconv.FormatInt(time.Now().Unix(), 10)
sign := md5hex(c.AppID + c.AppKey + ts + c.AppKey)
fields := url.Values{}
fields.Set("AppId", c.AppID)
fields.Set("AppKey", c.AppKey)
fields.Set("TimeStamp", ts)
fields.Set("Sign", sign)
out, err := c.post(fields, nil)
if err != nil {
return err
}
if int(out["code"].(float64)) != 200 {
return fmt.Errorf("init 失败: %v %v", out["code"], out["message"])
}
data := out["data"].(map[string]any)
c.ApiPassword = data["api_password"].(string)
return nil
}
// Call 调用任意 action
func (c *A7Client) Call(action string, params map[string]string) (map[string]any, error) {
if c.ApiPassword == "" {
if err := c.Init(); err != nil {
return nil, err
}
}
// 按 key 排序拼接,保证可复现
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
plain := "action=" + action
for _, k := range keys {
plain += "&" + k + "=" + url.QueryEscape(params[k])
}
ts := strconv.FormatInt(time.Now().Unix(), 10)
data, err := rc4Hex(c.ApiPassword, plain)
if err != nil {
return nil, err
}
data = toUpper(data)
sign := md5hex(c.ApiPassword + ts + data)
fields := url.Values{}
fields.Set("TimeStamp", ts)
fields.Set("Data", data)
fields.Set("Sign", sign)
return c.post(fields, map[string]string{"X-Api-Password": c.ApiPassword})
}
func toUpper(s string) string {
b := []byte(s)
for i, ch := range b {
if ch >= 'a' && ch <= 'f' {
b[i] = ch - 32
}
}
return string(b)
}使用示例
go
client := a7verify.New("150018", "YOUR_APP_KEY")
resp, err := client.Call("SingleLogin", map[string]string{
"Card": "UTDE-7TCX-N5AT-ZDSP",
"Mac": "TEST-ABC-123",
"DeviceName": "MyPC",
})
if err != nil {
log.Fatal(err)
}
code := int(resp["code"].(float64))
if code == 200 {
data := resp["data"].(map[string]any)
fmt.Println("token:", data["token"])
} else {
fmt.Println("失败:", resp["message"])
}注意事项
ApiPassword仅保存在结构体字段,请勿序列化落盘。- 明文参数按 key 排序拼接,保证可复现(顺序本身不影响服务端解析)。
- 更多接口参数见 API 参考。
相关链接
- 签名校验与 RC4 加密
- API 概述 · 两步模型
- 其它 SDK:Python · C# · Node.js · Java · C++ · 易语言