跳到主要内容

鉴权说明

除公开端点外,所有请求需使用 ak / skHMAC-SHA256 签名。 本页头名与规则以服务端实现为准

请求头

注意头名:本平台头名一律带 X-Gstack- 前缀,请严格按下表名称发送;沿用其它平台或旧文档的头名写法将返回 401 SIGN_MISSING
请求头必填说明
X-Gstack-AkAPI Key 标识(ak),公开标识,可与请求一同记录。
X-Gstack-TimestampUnix 秒(十进制字符串),与服务器偏差需 ≤ 5 分钟。
X-Gstack-Nonce一次性随机串,长度 ≥ 16,同一 ak 下不可重复。
X-Gstack-Signaturehex(HMAC-SHA256(sk, 待签串))小写 hex。
X-Gstack-Sign-Version签名版本,缺省 v1;存在时必须为 v1。

待签串规则(stringToSign)

5 段,以换行符 \n 连接, 末尾无换行。签名 = hex(HMAC-SHA256(sk, stringToSign))(小写)。

stringToSign
METHOD
PATH
TIMESTAMP
NONCE
hex(SHA256(body))
#说明
1METHODHTTP 方法,**大写**(如 GET / POST)
2PATH完整请求路径(如 /api/gstack/v1/whoami),不含 query
3TIMESTAMP与请求头 X-Gstack-Timestamp 逐字节相同(Unix 秒,不重排格式)
4NONCE与请求头 X-Gstack-Nonce 逐字节相同(≥16 字符,一次性)
5BODY_SHA256hex(SHA-256(原始 body 字节)),小写;空 body 为固定值

空 body 的 SHA-256 固定为 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

时间窗与 nonce

  • · 时间窗:|服务器时间 − TIMESTAMP| ≤ 5 分钟,超出即拒绝(请校准时钟)。
  • · nonce 一次性:验签通过后消费,同一 ak + 同一 nonce 再次使用即拒绝(防重放)。
  • · PATH 必须是完整请求路径(含 /api/gstack/v1/...), 不含 query(query 不参与签名)。
  • · TIMESTAMP / NONCE 与请求头逐字节相同,不做重格式化。

可粘贴示例

以下示例调用 GET /api/gstack/v1/whoami,与 快速开始 一致,可原样跑通。

python3(仅标准库)
import hashlib, hmac, os, time, urllib.request

AK   = "ak_live_在此填入你的 AK"
SK   = "sk_在此填入你的 SK"
BASE = "https://api.nanniwan.com"
PATH = "/api/gstack/v1/whoami"          # 完整路径,不含 query

body = b""                              # GET,无 body
ts    = str(int(time.time()))           # Unix 秒
nonce = os.urandom(16).hex()            # 长度 >= 16
body_sha = hashlib.sha256(body).hexdigest()

string_to_sign = "GET\n" + PATH + "\n" + ts + "\n" + nonce + "\n" + body_sha   # 5 段,无尾随换行
signature = hmac.new(SK.encode(), string_to_sign.encode(), hashlib.sha256).hexdigest()

req = urllib.request.Request(BASE + PATH, method="GET")
req.add_header("X-Gstack-Ak", AK)
req.add_header("X-Gstack-Timestamp", ts)
req.add_header("X-Gstack-Nonce", nonce)
req.add_header("X-Gstack-Signature", signature)
req.add_header("X-Gstack-Sign-Version", "v1")

with urllib.request.urlopen(req) as resp:
    print(resp.status, resp.read().decode())

失败排查

失败返回真实 HTTP 状态码,响应体 data.reason 为机器可读原因码。

HTTPreason文案常见原因
401SIGN_MISSING缺少签名四头(Ak/Timestamp/Nonce/Signature)未齐备,或 nonce 长度 <16
401SIGN_EXPIRED请求已过期,请校准时钟时间戳与服务器偏差超过 ±5 分钟(含时间戳非整数)
401SIGN_MISMATCH签名校验失败待签串或 sk 与实现不一致(含 path 带 query、body 未参与签名)
401NONCE_REPLAYED重复请求同一 ak + nonce 被重复使用(nonce 一次性)
401AK_INVALID凭据无效X-Gstack-Ak 不存在
401AK_REVOKED凭据已失效该 ak 已被吊销(status=0)
401SIGN_VERSION_UNSUPPORTED签名版本不受支持X-Gstack-Sign-Version 存在且 ≠ v1
413BODY_TOO_LARGE请求体过大body 超过服务端上限
400SUBJECT_OVERRIDE_FORBIDDEN请求包含禁止的主体标识body/query 中出现 merchant_id/user_id/tenant_id/subject_id 等禁止键(主体只从 Key 推导)
503NONCE_STORE_UNAVAILABLE服务暂不可用,请稍后重试nonce 存储(Redis)不可用 —— 按拒绝处理(fail-closed)

密钥安全须知

  • · sk 只在领取时显示一次,平台不提供二次查看;请立即保存到安全位置。
  • · 不要把 sk 写进前端代码、移动端 App、公开仓库或客户端调试日志——签名必须在服务端完成。
  • · claimSecret 是管理该 Key 的唯一凭证,请像保管 sk 一样保管;领取 / 重置后会轮换,需重新保存。
  • · sk 泄露时,请尽快在「密钥管理」页重置或吊销该凭据。