2024年2月19日发(作者:)
开宗明义,米扑科技在使用腾讯云的API接口签名中,按照官方示例开发PHP、Python的接口,经常会提示签名错误 1
2
3
4
5
6
7
8
9
{
"Response" : {
"Error" : {
"Code" :
"ureFailure" ,
"Message" :
"The provided credentials could not be validated. Please check your signature is correct."
},
"RequestId" :
"1ee6ae98-a971-ad9f-4ecc-abcd69ea1234"
}
}
本文原文,请参见米扑博客:Python
和 PHP
对腾讯云签名 hmac_sha256
算法实现经过多次尝试探究,发现原因有二:1)腾讯云官方示例不严谨,没有urlencode()
或 ()
编码导致提示签名错误2)腾讯官方只提供了PHP示例,没有提供Python示例,两者签名函数有一些细节
直接给出干货,下面示例是
米扑科技
封装好的腾讯云签名函数,以飨读者。腾讯云签名:/document/api/377/4214阿里云签名:/document_detail/米扑的官网:
PHP
签名示例 1
2
3
4
5
6
7
8
9 /**
*
签名并获取URL结果,json格式返回
*
* 1.
查询弹性IP列表, DescribeAddresses
* 2.
解绑弹性IP, DisassociateAddress
* 3.
释放弹性IP, ReleaseAddresses
* 4.
公网IP转弹性IP, TransformAddress
10
11
12
13
14
15
16
*
* @param string $req_action : DescribeAddresses, DisassociateAddress, ReleaseAddresses, TransformAddress
* @param string $params :
以 &
开头,
如 &xxx=yyy
*/
function
qcloud_eip_sign( $req_action = 'DescribeAddresses' 17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
,
$req_region='ap-beijing',
$req_extra_params='',
$retry_NUM=3) {global
$QCloud_SecretId;global
$QCloud_SecretKey;// $req_action='DescribeAddresses'// $req_region = 'ap-beijing'; // ap-guangzhou$req_method
=
'GET';
// GET POST$req_api
=
'/v2/';$req_version
=
'2017-03-12';$req_timestamp
=
strtotime(date('YmdHis'));
// 1402992826
41
42
43
44
45
46
47
48
$req_nonce
= rand(1000, 1000000);
//
随机正整数
$req_secretid
=
$QCloud_SecretId ;
//
密钥ID,用作参数
$req_secretkey
=
$QCloud_SecretKey ;
//
密钥key,用作加密
$req_signature_method
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
=
'HmacSHA256';
// HmacSHA1(默认), HmacSHA256$req_signature
=
'';// $req_uri = "/v2/?Action=DescribeAddresses// &Version=2017-03-12// &AddressIds.1=eip-hxlqja90// &Region=ap-beijing// &Timestamp=1402992826// &Nonce=345122// &Signature=pStJagaKsV2QdkJnBQWYBDByZ9YPBsOi// &SecretId=AKIDpY8cxBD2GLGK9sT0LaqIczGLFxTsoDF6//
请求方法 +
请求主机 +请求路径 + ? +
请求字符串$req_params
= sprintf("Action=%s&Region=%s&Version=%s&Timestamp=%s&Nonce=%s&SecretId=%s&SignatureMethod=%s%s",
$req_action,
$req_region,
$req_version,
$req_timestamp,
$req_nonce,
$req_secretid,
$req_signature_method,
$req_extra_params);
73
74
75
76
77
78
79
80
$req_params_array
=
explode ( "&" ,
$req_params );
sort( $req_params_array );
//
以value排序,value值为 Action=DescribeAddresses
、 Region=ap-beijing
$req_params2
= implode( "&"
81
,
$req_params_array);$req_uri
= sprintf("%s%s?%s",
$req_method,
$req_api,
$req_params2);$req_signature
= urlencode(base64_encode(hash_hmac('sha256',
$req_uri,
$req_secretkey, true)));
// urlencode(xxx)$req_url
= sprintf("%s?%s&Signature=%s",
$req_api,
$req_params2,
$req_signature);$res
= curl_url($req_url);$retry_idx
= 0;while(empty($res) &&
$retry_idx
<
$retry_NUM ) {
$retry_idx
+= 1;
$res
= curl_url( $req_url );
}
if(!empty($res)) {$resJson
= json_decode($res, true);$resJson
=
$resJson['Response'];echo
sprintf("
+++++ action : %s
resJson: ",
$req_action);print_r($resJson);return
$resJson;}else
{return
null;}}
$req_action_query
=
'DescribeAddresses' ;
//
查询弹性IP
$req_action_unbind
=
'DisassociateAddress' ;
//
解绑弹性IP
$req_action_release
=
'ReleaseAddresses' ;
//
释放弹性IP
$req_action_transform
=
'TransformAddress' ;
//
公网IP转弹性IP
$req_region
=
'ap-guangzhou' ;
$req_extra_params
=
'' ;
// 1.
查询弹性IP列表
$resJson
= qcloud_eip_sign( $req_action_query ,
$req_region );
var_dump( $resJson );
运行结果: 1
2
3
4
5
6
7
req_url: https: //eip . /v2/index .php?Action=DescribeAddresses&Nonce=585269&Region=ap-guangzhou&SecretId=AKIDSmAAAA2DABCDpTkBBBBMLMFwY0HM1234&SignatureMethod=HmacSHA256&Timestamp=1520429723&Version=20
array (size=3)
'TotalCount'
=> int 1
'AddressSet'
8
9
10
11
12
13
14
15
16
17
18
19
20
=>
array (size=1)
0 =>
array (size=11)
'AddressId'
=> string
'eip-qy123abc'
(length=12)
'AddressName'
=> null
'AddressIp'
=> string
'111.230.123.234'
(length=15)
'AddressStatus'
=> string
'BIND'
(length=4)
'InstanceId'
=> string
'ins-fabc1234'
(length=12)
'NetworkInterfaceId'
=> null
'PrivateAddressIp'
=> string
'10.104.245.26'
(length=14)
'IsArrears'
=> boolean
false
'IsBlocked'
=> boolean
false
'IsEipDirectConnection'
=> boolean
false
'CreatedTime'
=> string
'2018-03-07T12:46:26Z'
(length=20)
'RequestId'
=> string
'ad28067e-d1f9-4c47-932e-6bba1d123456'
(length=36)
代码说明:1)函数抽象封装签名方法,方便管理维护,减少开发工作量2)参数按照升序排列 explode(xxx) —> sort($req_params_array) —> implode(xxx)3)签名方法,需要添加 urlencode,否则经常提示签名错误,原因是未urlencode会有一些
空格、加号(+)、等号(=)等特殊字符$req_signature = urlencode(base64_encode(hash_hmac('sha256', $req_uri, $req_secretkey, true))); // urlencode(xxx)
Python
签名示例 1
2
3
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# # 2018-01-08import
time, datetime, os, jsonimport
urllib, urllib2import
hashlib, base64, hmac, randomimport
loggingimport
rsimport
sysreload(sys)aultencoding('utf-8')##
腾讯云API接口签名def
qcloud_eip_sign(req_action='DescribeAddresses', req_region='ap-beijing', req_extra_params='', retry_NUM=3):
28
29
30
31
32
33
34
35
req_method
=
'GET'
# GET POST
req_api
=
'/v2/'
req_version
=
'2017-03-12'
req_timestamp
=
int 36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(())
# 1520422452req_nonce
=
t(1000,
1000000)
#
随机正整数req_secretid
=
QCLOUD_SecretId
#
密钥ID,用作参数req_secretkey
=
QCLOUD_SecretKey
#
密钥key,用作加密req_signature_method
=
'HmacSHA256'
# HmacSHA1(默认), HmacSHA256req_signature
=
''# req_uri = "/v2/?Action=DescribeAddresses# &Version=2017-03-12# &AddressIds.1=eip-hxlqja90# &Region=ap-beijing# &Timestamp=1402992826# &Nonce=345122# &Signature=pStJagaKsV2QdkJnBQWYBDByZ9YPBsOi# &SecretId=AKIDpY8cxBD2GLGK9sT0LaqIczGLFxTsoDF6
60
61
62
63
64
65
66
#
请求方法 +
请求主机 +请求路径 + ? +
请求字符串
req_params
=
"Action=%s&Region=%s&Version=%s&Timestamp=%s&Nonce=%s&SecretId=%s&SignatureMethod=%s%s"
%
(req_action, req_region, req_version, req_timestamp, req_nonce, req_secretid, req_signature_method, req_extra_params)
req_params_array
=
req_( '&' )
67
68
69
70
71
72
73
74
75
76
77
78
79
req_params_array
=
sorted(req_params_array)
#
以value排序,value值为 Action=DescribeAddresses
、 Region=ap-beijingreq_params2
=
'&'.join(req_params_array);req_uri
=
"%s%s?%s"
%
(req_method, req_api, req_params2)req_signature
=
( base64.b64encode((req_secretkey, req_uri, digestmod=256).digest()) )
# (xxx)req_url
=
"%s?%s&Signature=%s"
%
(req_api, req_params2, req_signature)('qcloud_eip_sign() - req_url: %s'
%
(req_url))res
=
spider_url(req_url)retry_idx
=
0;while
not
res
and
retry_idx < retry_NUM:
retry_idx
+ =
1
res
=
spider_url(req_url)
if
res :resJson
=
(res)resJson
=
resJson['Response']print
"
+++++ action : %s
resJson: "%
(req_action,)return
resJsonelse:return
None;if
__name__
==
"__main__":req_action_query
=
'DescribeAddresses'
#
查询弹性IPreq_action_unbind
=
'DisassociateAddress'
#
解绑弹性IPreq_action_release
=
'ReleaseAddresses'
#
释放弹性IP
req_action_transform
=
'TransformAddress'
#
公网IP转弹性IP
req_region = 'ap-guangzhou'
req_extra_params
=
'';
# 1.
查询弹性IP列表
resJson
=
qcloud_eip_sign(req_action_query, req_region)
(resJson)
运行结果: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
req_url: https: //eip . /v2/index .php?Action=DescribeAddresses&Nonce=383782&Region=ap-guangzhou&SecretId=AKIDSmAAAA2DABCDpTkBBBBMLMFwY0HM1234&SignatureMethod=HmacSHA256&Timestamp=1520430569&Version=20 /rpIbQ5jPfe9tW3w9Slom4 %3D
{
"Response" : {
"TotalCount" : 1,
"AddressSet" : [
{
"AddressId" :
"eip-qy123abc" ,
"AddressName" : null,
16
17
18
19
20
21
22
23
"AddressIp" :
"111.230.123.234" ,
"AddressStatus" :
"BIND" ,
"InstanceId" :
"ins-fabc1234" ,
"NetworkInterfaceId" : null,
"PrivateAddressIp" :
"10.104.245.26" ,
"IsArrears" :
false ,
"IsBlocked" :
false ,
"IsEipDirectConnection" :
false ,
"CreatedTime" :
"2018-03-07T12:46:26Z"
}
],
"RequestId" :
"c2ab3f7f-9796-4ade-afb1-6bba1d123456"
}
}
代码说明:1)Python改写PHP代码,有一些细节,如 int(())、t(1000, 1000000)、sorted(req_params_array)等2)参数按照升序排列 ('&') —> sort($req_params_array) —> '&'.join(xxx)3)签名方法,需要添加 、base64.b64encode(xxx)、digest()
等,否则经常提示签名错误req_signature = ( base64.b64encode((req_secretkey, req_uri, digestmod=256).digest()) ) # (xxx)
Python
代码里,特别要注意 hmac
签名 sha256
后获取的是 digest(),而不是 hexdigest()
这里错了会一直提示签名错误!
总结之PHP和Python的对应关系1) PHP
签名 1
2
3
4
5
6
7
// sha1
$hmac_sha1_str
=
base64_encode (hash_hmac( "sha1" ,
$data ,
$secret_access_key ));
// HMAC-SHA1加密
$signature
= urlencode( $hmac_sha1_str );
//
编码URL
// sha256
$hmac_sha256_str
=
base64_encode (hash_hmac( "sha256" ,
$data ,
$secret_access_key ));
// HMAC-SHA256加密
$signature
= urlencode( $hmac_sha256_str );
//
编码URL
2)Python
签名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import
urllib, base54, hashlib, hmac
# sha1
hmac_sha1_str
=
base64.b64encode( (secret_access_key, data, digestmod = 1).digest() )
signature
=
(hmac_sha1_str)
# sha256
hmac_sha256_str
=
base64.b64encode( (secret_access_key, data, digestmod = 256).digest() )
signature
=
(hmac_sha256_str)
# sha256
hmac_sha256_str
=
base64.b64encode( (secret_access_key, data, digestmod = 256).hexdigest() )
# 16进制,错误
signature
=
(hmac_sha256_str)
发布评论