签名 - zmeet-ai/AI-Cloud GitHub Wiki

签名方式

申请安全凭证

在第一次使用云 API 之前,请前往 云 API 密钥页面 申请安全凭证。
安全凭证包括 AppId 和 AppSecret:

  • AppId 用于标识 API 调用者身份
  • AppSecret 用于加密签名字符串和服务器端验证签名字符串的密钥。
  • 用户必须严格保管安全凭证,避免泄露。

申请安全凭证的具体步骤如下:

  1. 登录 笔声云管理中心控制台 。
  2. 前往 云 API 密钥 的控制台页面
  3. 在 云 API 密钥 页面,单击【新建密钥】即可以创建一对 AppId/AppSecret。

生成签名串

有了安全凭证AppId 和 AppSecret后,就可以生成签名串了。以下是使用签名方法 v1 生成签名串的详细过程:

API 支持 GET 和 POST 请求。对于GET方法,只支持 Content-Type: application/x-www-form-urlencoded 协议格式。对于POST方法,目前支持 Content-Type: application/json 以及 Content-Type: multipart/form-data 两种协议格式,json 格式绝大多数接口均支持,multipart 格式只有特定接口支持,此时该接口不能使用 json 格式调用,参考具体业务接口文档说明。推荐使用 POST 请求,因为两者的结果并无差异,但 GET 请求只支持 32 KB 以内的请求包。

在示例中,不论公共参数或者接口的参数,我们尽量选择容易犯错的情况。在实际调用接口时,请根据实际情况来,每个接口的参数并不相同,不要照抄这个例子的参数和值。此外,这里只展示了部分公共参数和接口输入参数,用户可以根据实际需要添加其他参数,例如 Language 和 Token 公共参数(在 HTTP 头部设置,添加 X-AP- 前缀)。

假设用户的 AppId 和 AppSecret 分别是:

  • AppId: AKIDz8krbsJ5asddxXas241****
  • AppSecret: BG13Gu5t9xGARNpq8J41****

签名参数描述

参数名 描述
Authorization 认证凭证
X-AP-TS 当前时间 精确到秒

Authorization 组成方式如下

参数名
Algorithm V1-HMAC-SHA256
Scope 凭证范围,格式为 service 为产品名,必须与调用的产品域名一致。此示例计算结果是 asr
Credential 对应的AppId
Signature 签名结果
  1. X-AP-TS 必须是当前系统时间,且需确保系统时间和标准时间是同步的,如果相差超过五分钟则必定失败。如果长时间不和标准时间同步,可能导致运行一段时间后,请求必定失败,返回签名过期错误。

根据以上规则,示例中得到的待签名字符串如下:

V1-HMAC-SHA256
asr
AKIDz8krbsJ5asddxXas241****
f90bb38d001cc61bf999c3145f0abe732c5f8f29a8cae5ac2a2b7a61d02794b0

计算签名

1)伪代码:

appId = AKIDz8krbsJ5asddxXas241****
ts = 1672200376
secret = BG13Gu5t9xGARNpq8J41****
sign = hexEncode(sha256(secret,md5(appId + ts)))

sign 请注意,不同的编程语言,HMAC 库函数中参数顺序可能不一样,请以实际情况为准。此处的伪代码密钥参数 key 在前,消息参数 data 在后。通常标准库函数会提供二进制格式的返回值,需要取16进制的值也就是hex值

字段名称 解释
appId 平台申请的appId
secret 平台申请的秘钥
ts 对应时间戳 精确到秒
sign 对应签名结果 16进制值

此示例计算结果是 f90bb38d001cc61bf999c3145f0abe732c5f8f29a8cae5ac2a2b7a61d02794b0

2)拼接Authorization

按如下格式拼接 Authorization:

Authorization = 
      Algorithm + ';'
     'Scope=' + Scope + ';' +
     'Credential=' + AppId + ';' +
     'Signature=' + Sign + ';'
字段名称 描述
Algorithm 固定为V1-HMAC-SHA256
Scope 见上文,签名参数描述 此示例计算结果为 asr
Credential 见上文,此示例计算结果为 AKIDz8krbsJ5asddxXas241****
Signature 签名值,此示例计算结果为 f90bb38d001cc61bf999c3145f0abe732c5f8f29a8cae5ac2a2b7a61d02794b0

根据以上规则,示例中得到的值为:

 V1-HMAC-SHA256 ;Scope=asr;Credential=AKIDz8krbsJ5asddxXas241****;Signature=f90bb38d001cc61bf999c3145f0abe732c5f8f29a8cae5ac2a2b7a61d02794b0

最终完整的调用信息如下:

POST https://asr.cloud.abcpen.com/
Authorization:  V1-HMAC-SHA256 ;Scope=asr;Credential=AKIDz8krbsJ5asddxXas241****;Signature=f90bb38d001cc61bf999c3145f0abe732c5f8f29a8cae5ac2a2b7a61d02794b0
Content-Type: application/json; charset=utf-8
Host: asr.cloud.abcpen.com
X-AP-TS: 1672200376

签名演示

Java

public class SignDemo {
    private final static Charset UTF8 = StandardCharsets.UTF_8;

    private final static String JSON = "application/json; charset=utf-8";
    private final static String ALGORITHM = "V1-HMAC-SHA256";

    public static String hmac256(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return byteArrayToHexString(mac.doFinal(msg.getBytes(UTF8))).toLowerCase();
    }


    public static final String md5(String pstr) {
        char[] md5String = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] btInput = pstr.getBytes();
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char[] str = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) { // i = 0
                byte byte0 = md[i]; // 95
                str[k++] = md5String[byte0 >>> 4 & 0xf]; // 5
                str[k++] = md5String[byte0 & 0xf]; // F
            }

            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }


    private static String byteArrayToHexString(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1)
                hs.append('0');
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }


    public static void main(String[] args) throws Exception {
        String host = "cloud-test.abcpen.com";
        String path = "/ai/v2/tts/audioPackage";


        // ************* 步骤 1:计算签名 *************
        String appId = "AKIDz8krbsJ5asddxXas241****";
        String appSecret = "BG13Gu5t9xGARNpq8J41****";
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);

        //待签名的message
        String message = md5(appId + timestamp);
        String sign = hmac256(appSecret.getBytes(StandardCharsets.UTF_8), message);
        System.out.println("sign = " + sign);

        // ************* 步骤 2:拼接 Authorization *************
        String service = "asr";
        String algorithm = "V1-HMAC-SHA256";


        ZoneId defaultZone = ZoneId.systemDefault();
   

        StringBuilder sb = new StringBuilder();
        String authorization = sb.append(algorithm).append(";")
                .append("Scope=").append(service).append(";")
                .append("Credential=").append(appId).append(";")
                .append("Signature=").append(sign).toString();

        System.out.println("authorization = " + authorization);


        TreeMap<String, String> headers = new TreeMap<String, String>();
        headers.put("Authorization", authorization);
        headers.put("Content-Type", JSON);
        headers.put("Host", host);
        headers.put("X-AP-TS", timestamp);


        StringBuilder curl = new StringBuilder();
        curl.append("curl -X GET https://").append(host).append(path)
                .append(" -H "Authorization: ").append(authorization).append(""")
                .append(" -H "Host: ").append(host).append(""")
                .append(" -H "X-AP-TS: ").append(timestamp).append(""");
        System.out.println(curl);

    }
}

Python

import hashlib
import hmac

def get_auth(scop,ts, app_id, app_secret):
    tt = (app_id + ts).encode('utf-8')
    md5 = hashlib.md5()
    md5.update(tt)
    baseString = md5.hexdigest()
    baseString = bytes(baseString, encoding='utf-8')
    apiKey = app_secret.encode('utf-8')
    signa = hmac.new(apiKey, baseString, hashlib.sha256).hexdigest()
    return "V1-HMAC-SHA256;Scope={};Credential={};Signature={}".format(scop,app_id,signa)