本文目录HMAC-SHA256 签名流程第一步:生成请求元数据第二步:构建签名字符串第三步:计算签名第四步:设置请求头代码示例Access Sign(请求体签名)接口认证方式

身份认证 ​

HashNut 使用 HMAC-SHA256 签名来验证 API 请求。部分接口使用请求头签名,另一些则在请求体中使用 accessSign 字段。

HMAC-SHA256 签名流程 ​

签名过程包含四个步骤:

第一步:生成请求元数据 ​

为每个请求生成一个 UUID 和一个 Unix 时间戳(秒)。

第二步:构建签名字符串 ​

将三个部分无分隔符地拼接在一起:

signString = uuid + timestamp + requestBody

其中 requestBody 是请求体的 JSON 字符串。

第三步:计算签名 ​

使用您的 Secret Key 计算 HMAC-SHA256,然后对结果进行 Base64 编码:

signature = base64( hmac_sha256( secretKey, signString ) )

第四步:设置请求头 ​

在 HTTP 请求中包含以下请求头:

请求头说明
hashnut-request-uuid第一步中生成的 UUID
hashnut-request-timestamp第一步中生成的 Unix 时间戳
hashnut-request-signBase64 编码的 HMAC-SHA256 签名
Content-Type必须为 application/json

代码示例 ​

java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.UUID;

public class HashNutSign {
    public static String[] sign(String secretKey, String body) throws Exception {
        String reqUUID = UUID.randomUUID().toString();
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);

        String signString = reqUUID + timestamp + body;

        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secretKey.getBytes(), "HmacSHA256"));
        String signature = Base64.getEncoder().encodeToString(
                mac.doFinal(signString.getBytes()));

        return new String[]{reqUUID, timestamp, signature};
    }
}
go
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"time"

	"github.com/google/uuid"
)

func sign(secretKey, body string) (reqUUID, timestamp, signature string) {
	reqUUID = uuid.New().String()
	timestamp = fmt.Sprintf("%d", time.Now().Unix())

	signString := reqUUID + timestamp + body

	mac := hmac.New(sha256.New, []byte(secretKey))
	mac.Write([]byte(signString))
	signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return reqUUID, timestamp, signature
}
js
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');

function sign(secretKey, body) {
  const reqUUID = uuidv4();
  const timestamp = Math.floor(Date.now() / 1000).toString();

  const signString = reqUUID + timestamp + body;

  const signature = crypto
    .createHmac('sha256', secretKey)
    .update(signString)
    .digest('base64');

  return { reqUUID, timestamp, signature };
}
python
import hmac
import hashlib
import base64
import uuid
import time

def sign(secret_key: str, body: str):
    req_uuid = str(uuid.uuid4())
    timestamp = str(int(time.time()))

    sign_string = req_uuid + timestamp + body

    signature = base64.b64encode(
        hmac.new(
            secret_key.encode(),
            sign_string.encode(),
            hashlib.sha256
        ).digest()
    ).decode()

    return req_uuid, timestamp, signature

Access Sign(请求体签名) ​

部分接口(如查询订单和确认支付)使用简化的签名方式,将签名作为 accessSign 字段包含在请求体中,而非放在请求头中。

accessSign 的计算方式:

accessSign = base64( hmac_sha256( secretKey, requestBodyWithoutAccessSign ) )

其中 requestBodyWithoutAccessSign 是添加 accessSign 字段之前的请求体 JSON 字符串。

接口认证方式 ​

接口认证方式说明
POST /v4.0.0/api/orders/create请求头签名创建订单
POST /v4.0.0/api/orders/cancel请求头签名取消订单
POST /v4.0.0/api/orders/query请求体 accessSign查询订单
POST /v4.0.0/pay/orders/confirm请求体 accessSign确认支付
POST /v4.0.0/api/orders/supplements请求体 accessSign查询补单
POST /v4.0.0/config/*无需认证公共配置接口

TIP

如果您使用 Go SDK,签名将自动处理。您只需在初始化客户端时提供 Access Key ID 和 Secret Key。