身份认证
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-sign | Base64 编码的 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, signatureAccess 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。
