签名介绍
我们的签名算法。
推荐使用我们已经封装好的SDK或模块
若您的语言我们已经有提供SDK支持的前提下(PHP、Python、NodeJS、Golang和Java),我们不推荐您重新封装签名。
直接使用 SDK 进行开发,可以帮您省去不少对接的工作量。
自行对接
如果您坚持自行对接签名,我们强烈建议您使用这个调试工具来校对签名:https://www.anquanssl.com/debugtool/
1. 系统参数
系统参数有以下这些:
accessKeyId: 请求者的accessKeyId,申请 API(代理商)权限后由系统分配。timestamp: 时间戳,格式为YYYY-mm-ddTHH:ii:ssZ,如2019-10-10T12:00:01Z,特别注意的是需要获取中华人民共和国北京时区下的时间,且误差不能超过 15 分钟。nonce: 幂等 token,格式为英文大小写字母加数字,长度 32 字符内,开发者需要保证在 24 小时内不冲突。sign: 签名,将请求 API 的 URI+系统参数+业务参数排序后做为数据,由accessKeySecret进行 sha256 摘要后 base64 得到。具体生成规则请见签名。
提示
PHP 代码示例
<?php
$defaultTimeZone = date_default_timezone_get(); //获取签名前的时区
date_default_timezone_set('PRC'); //设置到东八区
$parameters['accessKeyId'] = $this->accessKeyId;
$parameters['nonce'] = uniqid();
$parameters['timestamp'] = date('Y-m-d\TH:i:s\Z'); //获取时间戳
date_default_timezone_set($defaultTimeZone); //还原到签名前的时区
2. 参数整理
首先以业务参数优先,将系统参数合并进业务参数:
提示
PHP 代码示例
<?php
$defaultTimeZone = date_default_timezone_get(); //获取签名前的时区
date_default_timezone_set('PRC'); //设置到东八区
$parameters['accessKeyId'] = $this->accessKeyId;
$parameters['nonce'] = uniqid();
$parameters['timestamp'] = date('Y-m-d\TH:i:s\Z'); //获取时间戳
date_default_timezone_set($defaultTimeZone); //还原到签名前的时区
// 以上是之前的代码
$business_parameters = [/* 业务参数 */];
// 将业务参数中的两头空格移除
function trimize($business_parameters) {
foreach($business_parameters as $key => $value) {
if (is_string($value)) {
// 当 value 为数组时, 需要对 value 下的子项也 trim 操作
$business_parameters[$key] = trim($value);
if ('' === $business_parameters[$key]) {
$business_parameters[$key] = null;
}
} else if (is_array($value)) {
$business_parameters[$key] = trimize($value);
}
}
return $business_parameters;
}
$business_parameters = trimize($business_parameters);
$parameters = array_merge($parameters, isset($arguments[1]) ? $arguments[1] : []);
ksort($parameters);
3. URLEncode 以及 HTTP_Build_Query() 详解
a. URLEncode(键、值均要进行编码):
我们服务器要求对接方对请求参数中出现的以下字符进行替换编码,对于不存在于下面字典的字符(例如中文),可使用语言自带的urlencode函数进行处理:
| 源字符 | 编码后 | 备注 |
|---|---|---|
| + | 空格 |
\n | %0A | 回车换行 |
\r | %0D | |
! | %21 | |
" | %22 | |
# | %23 | |
$ | %24 | |
% | %25 | |
& | %26 | |
' | %27 | |
( | %28 | |
) | %29 | |
* | %2A | |
+ | %2B | |
, | %2C | |
/ | %2F | |
: | %3A | |
; | %3B | |
< | %3C | |
= | %3D | |
> | %3E | |
? | %3F | |
@ | %40 | |
[ | %5B | |
\ | %5C | |
] | %5D | |
^ | %5E | |
` | %60 | |
{ | %7B | |
| | %7C | |
} | %7D | |
~ | %7E |
b. HTTP_Build_Query:
例1
{
"accessKeyId": "test_key=",
"timestamp": "2024-04-23T02:50:50Z",
"nonce": "/n241z!"
}
应转换为
accessKeyId=test_key%3D&nonce=%2Fn241z%21×tamp=2024-04-23T02%3A50%3A50Z
例2
{
"accessKeyId": "test_key=",
"domain_dcv": {
"mydomain.com": "dns",
"*.mydomain.com": "dns",
"bbs.mydomain2.com": "webmaster@mydomain2.com",
},
"timestamp": "2024-04-23T02:50:50Z",
"nonce": "/n241z!"
}
应转换为
accessKeyId=test_key%3D&domain_dcv%5Bbbs.mydomain2.com%5D=webmaster%40mydomain2.com&domain_dcv%5Bmydomain.com%5D=dns&domain_dcv%5B%2A.mydomain2.com%5D=dns&nonce=%2Fn241z%21×tamp=2024-04-23T02%3A50%3A50Z
4. 签名
将请求的 API 完整相对地址(不带域名部分和?后参数部分),与第二部合并后的所有参数,以 urlencode(key1)=urlencode(value1)&urlencode(key2)=urlencode(value2)的方式拼到一个字串,使用 sha256 以 accessKeySecret 为加密 KEY 签名:
提示
PHP 代码示例
<?php
$defaultTimeZone = date_default_timezone_get(); //获取签名前的时区
date_default_timezone_set('PRC'); //设置到东八区
$parameters['accessKeyId'] = $this->accessKeyId;
$parameters['nonce'] = uniqid();
$parameters['timestamp'] = date('Y-m-d\TH:i:s\Z'); //获取时间戳
date_default_timezone_set($defaultTimeZone); //还原到签名前的时区
$business_parameters = [/* 业务参数 */];
// 将业务参数中的两头空格移除
function trimize($business_parameters) {
foreach($business_parameters as $key => $value) {
if (is_string($value)) {
// 当 value 为数组时, 需要对 value 下的子项也 trim 操作
$business_parameters[$key] = trim($value);
if ('' === $business_parameters[$key]) {
$business_parameters[$key] = null;
}
} else if (is_array($value)) {
$business_parameters[$key] = trimize($value);
}
}
return $business_parameters;
}
$business_parameters = trimize($business_parameters);
$parameters = array_merge($parameters, isset($arguments[1]) ? $arguments[1] : []);
ksort($parameters);
// 以上是之前的代码
$parameters['sign'] = base64_encode(hash_hmac(
'sha256',
$resource . '?' .http_build_query($parameters),
$this->accessKeySecret,
true // 务必选择raw类型,而不要十六进制类型
));
$uri = $this->apiOrigin . $resource;
//接下来可以向 $uri 发起请求了,GET/POST参数就是 $parameters