开放 API 调用说明文档

欢迎使用云签名授权中心开放接口。外部开发者可以通过分配的 API 凭证(ID 与 Secret)以安全签名机制直接调用本中心提供的签名引擎,免除了使用 Wails 客户端的限制。

概述与 API 鉴权说明

为保护服务器接口不被恶意篡改与抓包重放,所有调用 /api/sign/* 的开放算签接口均需在请求 Header 中携带 API 凭证和防重放动态签名。

请求 URL / Base URL
生产环境接口请求基准地址为:https://js.newso.top/
凭证获取方式
1. 开放接口的 ID 即为您注册/创建账户时的手机号
2. 开放接口的 Secret 密钥可在系统管理后台由管理员分配或在操作栏点击“重置密钥”生成,请妥善保管,切勿在客户端明文传输。

Header 认证三要素

Header 键名 类型 说明与规则
X-Api-Appid string 外部开发者的 AppID(即分配的登录手机号)
X-Api-Timestamp string 秒级 UNIX 时间戳(如 1718000000)。服务器校验该时间戳与当前系统时间差,相差超过 ±30 秒 的请求会被拦截。
X-Api-Sign string 由开发者计算的动态签名验证值(64位小写 HEX 字符串)

X-Api-Sign 签名计算方法

1构造待签名串:拼接 Timestamp (十进制整数字符串) 与当前请求的 URL Path (包含前导斜杠,如 /api/sign/xhs)。
拼接公式:待签串 = Timestamp + Path。例:"1718000000/api/sign/xhs"
2做 HMAC-SHA256 签算:使用分配 of Secret 密钥作为 Key,对待签名串以标准 HMAC-SHA256 算法算签。
3转换为 HEX 串:将哈希摘要字节流转换为十六进制小写格式,即可得到 X-Api-Sign 头部的值。
⚠️ 极其重要注意事项 (不同接口 Path 必须更换)
待签串中的 Path 必须与您当前调用的 API 接口路径完全一致!例如:
  • 如果调用小红书算签接口,Path 必须为:/api/sign/xhs
  • 如果调用抖音 Post/Query 算签接口,Path 必须为:/api/sign/dy/post
  • 如果调用抖音评论 A-Bogus 算签接口,Path 必须为:/api/sign/dy/cmt
切勿在代码中硬编码某一个固定 Path!如果请求的接口与签名时拼接的 Path 不匹配,服务器会直接拦截并返回 401 签名错误。

📖 签名计算详细步骤与对比示例

为了方便您和 AI 编程助手调试,以下是使用密钥 initialtestsecret1234567890abc,在时间戳为 1718000000 时计算的两个真实签名对比,供您核对计算逻辑是否正确:

对比维度 示例 A:小红书算签 示例 B:抖音 Post 算签
实际调用接口 /api/sign/xhs /api/sign/dy/post
时间戳 Timestamp 1718000000 1718000000
拼接所用的 Path /api/sign/xhs /api/sign/dy/post
待签名拼接串 "1718000000/api/sign/xhs" "1718000000/api/sign/dy/post"
分配的 Secret Key initialtestsecret1234567890abc initialtestsecret1234567890abc
最终 X-Api-Sign (HEX) 71163c04d96e4bd408f9939893b65d1efcda6ec10565f663749b3c160f69b3b1 d3057849e3de887a300b432128b7cd1adc7f3791c805204c1458a1bb669d106f

用户注册

外部用户注册接口,注册成功后系统将自动为该手机号用户初始化点数余额与 32 位随机 API Secret。

POST /api/auth/register

请求参数 (JSON Body):

字段名 类型 必填 说明
nickname string 用户昵称
phone string 手机号,全网唯一,将用作 AppID
password string 登录密码

返回响应 (JSON):

{
  "code": 1,
  "msg": "注册成功",
  "data": {
    "phone": "13999999999"
  }
}

用户登录 (排他会话)

用户登录云端。登录成功后返回的 session_id 需用于 Wails 客户端的心跳及身份验证。本系统支持异地挤下线逻辑,若未开启 force 参数且前处登录未退出,则需要提示前端确认。

POST /api/auth/login

请求参数 (JSON Body):

字段名 类型 必填 说明
phone string 手机号
password string 密码
force boolean 是否强制挤掉上次登录。传 true 将直接踢掉旧连接并强制登录;不传默认为 false

冲突响应 (有其它设备在线且 force=false):

{
  "code": 0,
  "msg": "上次登录还没有退出",
  "data": {
    "conflict": true
  }
}

成功响应 (200 OK):

{
  "code": 1,
  "msg": "登录成功",
  "data": {
    "session_id": "84bd4b1c-c9d3-4f91-a1e6-81cf42738a16",
    "nickname": "测试开发者",
    "phone": "13999999999",
    "role": "user",
    "balance": 100,
    "expires_at": "2026-07-16T08:40:00+08:00"
  }
}

心跳保活检测

Session 模式的客户端心跳检测。调用该接口可以保持客户端处于“在线”状态,并在前台被他人异地登录挤下线时,收到断开提示。

POST /api/auth/heartbeat

请求 Header 注入:

Header 键名 类型 必填 说明
X-Auth-Session string 登录接口返回的 session_id 凭证。

在线响应 (200 OK):

{
  "code": 1,
  "msg": "成功",
  "data": {
    "token_balance": 99.5,
    "expires_at": "2026-07-16 08:40:00"
  }
}

异地踢下线响应 (401 Unauthorized):

{
  "code": 0,
  "msg": "您的账号已在其他地方登录,当前连接已被强制断开",
  "data": {
    "code": "session_replaced"
  }
}

抖音 Post/Query 算签

用于计算抖音请求所需的 X-Bogus 签名值。成功计算会扣除账户 1.0 个点数(Token)。

POST /api/sign/dy/post
此为受保护的算签接口,必须在 Header 注入鉴权三要素:X-Api-Appid, X-Api-Timestamp, X-Api-Sign

请求参数 (JSON Body):

字段名 类型 必填 说明
params string 待拼接 X-Bogus 的完整 Query 请求参数串,不含 ? (例如 device_id=123&iid=456)
body string POST 请求的内容,如无传空或不传
user_agent string 发起请求的浏览器 User-Agent 字符串。签算引擎需要对 UA 进行混淆提取

返回响应 (200 OK):

{
  "code": 1,
  "msg": "成功",
  "data": {
    "x_bogus": "DFSzSwVLdUtANW/MSBfQ8L9WXBJz"
  }
}

抖音评论 A-Bogus 算签

用于计算抖音评论、搜索等接口所需的 A-Bogus 签名。成功计算扣除 1.0 个点数(Token)。

POST /api/sign/dy/cmt
必须在 Header 注入鉴权三要素:X-Api-Appid, X-Api-Timestamp, X-Api-Sign

请求参数 (JSON Body):

字段名 类型 必填 说明
url string 抖音评论接口的完整请求 URL
user_agent string 发起请求的浏览器 User-Agent 字符串

返回响应 (200 OK):

{
  "code": 1,
  "msg": "成功",
  "data": {
    "a_bogus": "DFSzSwVLdUtANW/MSBfQ8L9WXBJz..."
  }
}

小红书全套头部算签

全套生成小红书防爬虫所需的 x-s, x-s-common, x-t, x-xray-traceid 等自定义头。成功扣除 1.0 个点数(Token)。

POST /api/sign/xhs
必须在 Header 注入鉴权三要素:X-Api-Appid, X-Api-Timestamp, X-Api-Sign

请求参数 (JSON Body):

字段名 类型 必填 说明
method string 请求方法:"GET""POST" (必须大写)
uri string API 请求的 Path 路径与 Query 参数 (例如 /api/sns/v6/homefeed?category=homefeed_recommend)
cookie string 小红书账号的 Cookie 串。算签模块需从 Cookie 中提取 a1 校验位。
payload any 若是 POST 请求,传传参的 JSON 原始 Body 对象;GET 请求可传 null

返回响应 (200 OK):

{
  "code": 1,
  "msg": "成功",
  "data": {
    "x-s": "XYT_2UQhPsHCH0c1PUhMHjIj2erjwjQ...",
    "x-s-common": "2UQAPsHC+aIjqArjwjHjNsQ...",
    "x-t": "1718000000000",
    "x-xray-traceid": "cf66f14d5fcf1298ab3dbcfa4c18b676"
  }
}

Python 对接调用示例

使用 Python requests 库对待签名接口进行签算及发送算签请求的完整范例:

import time
import hmac
import hashlib
import requests

# 开发者密钥配置
APPID = "13999999999"  # 你的手机号
SECRET = "your_allocated_secret_key"  # 你的 32 位 Secret 密钥

def get_api_headers(path):
    timestamp = str(int(time.time()))
    # 拼接签名串: Timestamp + Path
    message = timestamp + path
    
    # HMAC-SHA256 签名计算
    sig = hmac.new(
        SECRET.encode('utf-8'),
        message.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    
    return {
        "X-Api-Appid": APPID,
        "X-Api-Timestamp": timestamp,
        "X-Api-Sign": sig,
        "Content-Type": "application/json"
    }

# 示例:请求小红书签名服务
url = "https://js.newso.top/api/sign/xhs"
path = "/api/sign/xhs"

headers = get_api_headers(path)
data = {
    "method": "GET",
    "uri": "/api/sns/v6/homefeed?category=homefeed_recommend",
    "cookie": "a1=18f8d9bxxxxxx;",
    "payload": None
}

try:
    resp = requests.post(url, headers=headers, json=data)
    print("状态码:", resp.status_code)
    print("签名头响应:", resp.json())
except Exception as e:
    print("请求异常:", e)

Go 对接调用示例

Go 语言下进行 API 开放鉴权并向云签名服务发送请求的代码:

package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"time"
)

const (
	AppID  = "13999999999"
	Secret = "your_allocated_secret_key"
)

func main() {
	url := "https://js.newso.top/api/sign/xhs"
	path := "/api/sign/xhs"
	timestamp := time.Now().Unix()

	// 1. 签名串: Timestamp + Path
	rawMessage := fmt.Sprintf("%d%s", timestamp, path)
	mac := hmac.New(sha256.New, []byte(Secret))
	mac.Write([]byte(rawMessage))
	sign := hex.EncodeToString(mac.Sum(nil))

	// 2. 构造请求体
	reqBody, _ := json.Marshal(map[string]interface{}{
		"method":  "GET",
		"uri":     "/api/sns/v6/homefeed?category=homefeed_recommend",
		"cookie":  "a1=18f8d9bxxxxxx;",
		"payload": nil,
	})

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(reqBody))
	
	// 3. 设定 Header
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Api-Appid", AppID)
	req.Header.Set("X-Api-Timestamp", strconv.FormatInt(timestamp, 10))
	req.Header.Set("X-Api-Sign", sign)

	// 4. 发送请求
	client := &http.Client{Timeout: 5 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("请求出错:", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println("状态码:", resp.StatusCode)
	fmt.Println("返回数据:", string(body))
}