签名 - zmeet-ai/AI-Cloud GitHub Wiki
签名方式
申请安全凭证
在第一次使用云 API 之前,请前往 云 API 密钥页面 申请安全凭证。
安全凭证包括 AppId 和 AppSecret:
- AppId 用于标识 API 调用者身份
- AppSecret 用于加密签名字符串和服务器端验证签名字符串的密钥。
- 用户必须严格保管安全凭证,避免泄露。
申请安全凭证的具体步骤如下:
- 登录 笔声云管理中心控制台 。
- 前往 云 API 密钥 的控制台页面
- 在 云 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 | 签名结果 |
- 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)