make clear the purpose and main theme from the very beginning , MIPO technology is using Tencent cloud API In the interface signature , Follow the official example to develop PHP、Python The interface of , Often prompts for signature errors
1
2
3
4
5
6
7
8
9
|
{
"Response"
: {
"Error"
: {
"Code"
:
"InvalidParameter.SignatureFailure"
,
"Message"
:
"The provided credentials could not be validated. Please check your signature is correct."
},
"RequestId"
:
"1ee6ae98-a971-ad9f-4ecc-abcd69ea1234"
}
}
|
The original text of this article , See MIPO blog :
Python and PHP Sign for Tencent cloud hmac_sha256 Algorithm implementation
After many attempts to explore , There are two reasons :
1) Tencent cloud official example is not rigorous , No, urlencode() or urllib.quote() Encoding causes prompt signature error
2) Tencent only provides PHP Example , Not provided Python Example , Both signature functions have some details
Give dry goods directly , The following example is MIPO technology Encapsulated Tencent cloud signature function , To readers .
Tencent cloud signature :https://cloud.tencent.com/document/api/377/4214
Alibaba cloud signature :https://help.aliyun.com/document_detail/35735.html
MIPO's official website :https://mimvp.com
PHP Signature example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
/**
* Sign and get URL result ,json Format return
*
* 1. Query elasticity IP list , DescribeAddresses
* 2. Unbound elasticity IP, DisassociateAddress
* 3. Release elasticity IP, ReleaseAddresses
* 4. Public network IP Rotational elasticity IP, TransformAddress
*
* @param string $req_action : DescribeAddresses, DisassociateAddress, ReleaseAddresses, TransformAddress
* @param string $params : With & start , Such as &xxx=yyy
*/
function
qcloud_eip_sign(
$req_action
=
'DescribeAddresses'
,
$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
=
'eip.api.qcloud.com/v2/index.php'
;
$req_version
=
'2017-03-12'
;
$req_timestamp
=
strtotime
(
date
(
'YmdHis'
));
// 1402992826
$req_nonce
= rand(1000, 1000000);
// Random positive integers
$req_secretid
=
$QCloud_SecretId
;
// secret key ID, Used as a parameter
$req_secretkey
=
$QCloud_SecretKey
;
// secret key key, Used as encryption
$req_signature_method
=
'HmacSHA256'
;
// HmacSHA1( Default ), HmacSHA256
$req_signature
=
''
;
// $req_uri = "https://eip.api.qcloud.com/v2/index.php?Action=DescribeAddresses
// &Version=2017-03-12
// &AddressIds.1=eip-hxlqja90
// &Region=ap-beijing
// &Timestamp=1402992826
// &Nonce=345122
// &Signature=pStJagaKsV2QdkJnBQWYBDByZ9YPBsOi
// &SecretId=AKIDpY8cxBD2GLGK9sT0LaqIczGLFxTsoDF6
// Request method + Request host + Request path + ? + Request string
$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
);
$req_params_array
=
explode
(
"&"
,
$req_params
);
sort(
$req_params_array
);
// With value Sort ,value The value is Action=DescribeAddresses 、 Region=ap-beijing
$req_params2
= implode(
"&"
,
$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(
"https://%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(
"<br><br> +++++ action : %s <br><br> resJson: "
,
$req_action
);
print_r(
$resJson
);
return
$resJson
;
}
else
{
return
null;
}
}
$req_action_query
=
'DescribeAddresses'
;
// Query elasticity IP
$req_action_unbind
=
'DisassociateAddress'
;
// Unbound elasticity IP
$req_action_release
=
'ReleaseAddresses'
;
// Release elasticity IP
$req_action_transform
=
'TransformAddress'
;
// Public network IP Rotational elasticity IP
$req_region
=
'ap-guangzhou'
;
$req_extra_params
=
''
;
// 1. Query elasticity IP list
$resJson
= qcloud_eip_sign(
$req_action_query
,
$req_region
);
var_dump(
$resJson
);
|
Running results :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
req_url: https:
//eip
.api.qcloud.com
/v2/index
.php?Action=DescribeAddresses&Nonce=585269&Region=ap-guangzhou&SecretId=AKIDSmAAAA2DABCDpTkBBBBMLMFwY0HM1234&SignatureMethod=HmacSHA256&Timestamp=1520429723&Version=2017-03-12&Signature=8U6i3BKBWYWoit3t1egIE9ZC%2BdWtI46QuHLc%2FbhaWWg%3D
array (size=3)
'TotalCount'
=> int 1
'AddressSet'
=>
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)
|
Code instructions :
1) Function abstraction encapsulates signature methods , Easy to manage and maintain , Reduce development effort
2) The parameters are arranged in ascending order explode(xxx) —> sort($req_params_array) —> implode(xxx)
3) Signature method , Need to add urlencode, Otherwise, you will often be prompted for wrong signature , The reason is not urlencode There will be some. Space 、 plus (+)、 Equal sign (=) Equal special character
$req_signature = urlencode(base64_encode(hash_hmac('sha256', $req_uri, $req_secretkey, true))); // urlencode(xxx)
Python Signature example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
# mimvp.com
# 2018-01-08
import
time, datetime, os, json
import
urllib, urllib2
import
hashlib, base64, hmac, random
import
logging
import
logging.handlers
import
sys
reload
(sys)
sys.setdefaultencoding(
'utf-8'
)
## Tencent cloud API Interface signature
def
qcloud_eip_sign(req_action
=
'DescribeAddresses'
, req_region
=
'ap-beijing'
, req_extra_params
=
'', retry_NUM
=
3
):
req_method
=
'GET'
# GET POST
req_api
=
'eip.api.qcloud.com/v2/index.php'
req_version
=
'2017-03-12'
req_timestamp
=
int
(time.time())
# 1520422452
req_nonce
=
random.randint(
1000
,
1000000
)
# Random positive integers
req_secretid
=
QCLOUD_SecretId
# secret key ID, Used as a parameter
req_secretkey
=
QCLOUD_SecretKey
# secret key key, Used as encryption
req_signature_method
=
'HmacSHA256'
# HmacSHA1( Default ), HmacSHA256
req_signature
=
''
# req_uri = "https://eip.api.qcloud.com/v2/index.php?Action=DescribeAddresses
# &Version=2017-03-12
# &AddressIds.1=eip-hxlqja90
# &Region=ap-beijing
# &Timestamp=1402992826
# &Nonce=345122
# &Signature=pStJagaKsV2QdkJnBQWYBDByZ9YPBsOi
# &SecretId=AKIDpY8cxBD2GLGK9sT0LaqIczGLFxTsoDF6
# Request method + Request host + Request path + ? + Request string
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_params.split(
'&'
)
req_params_array
=
sorted
(req_params_array)
# With value Sort ,value The value is Action=DescribeAddresses 、 Region=ap-beijing
req_params2
=
'&'
.join(req_params_array);
req_uri
=
"%s%s?%s"
%
(req_method, req_api, req_params2)
req_signature
=
urllib.quote( base64.b64encode(hmac.new(req_secretkey, req_uri, digestmod
=
hashlib.sha256).digest()) )
# urllib.quote(xxx)
req_url
=
"https://%s?%s&Signature=%s"
%
(req_api, req_params2, req_signature)
logger.info(
'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
=
json.loads(res)
resJson
=
resJson[
'Response'
]
print
"<br><br> +++++ action : %s <br><br> resJson: "
%
(req_action,)
return
resJson
else
:
return
None
;
if
__name__
=
=
"__main__"
:
req_action_query
=
'DescribeAddresses'
# Query elasticity IP
req_action_unbind
=
'DisassociateAddress'
# Unbound elasticity IP
req_action_release
=
'ReleaseAddresses'
# Release elasticity IP
req_action_transform
=
'TransformAddress'
# Public network IP Rotational elasticity IP
req_region
=
'ap-guangzhou'
req_extra_params
=
'';
# 1. Query elasticity IP list
resJson
=
qcloud_eip_sign(req_action_query, req_region)
print
json.dumps(resJson)
|
Running results :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
req_url: https:
//eip
.api.qcloud.com
/v2/index
.php?Action=DescribeAddresses&Nonce=383782&Region=ap-guangzhou&SecretId=AKIDSmAAAA2DABCDpTkBBBBMLMFwY0HM1234&SignatureMethod=HmacSHA256&Timestamp=1520430569&Version=2017-03-12&Signature=Tsgwx2GV/%2BopDlHiMUg3H
/rpIbQ5jPfe9tW3w9Slom4
%3D
{
"Response"
: {
"TotalCount"
: 1,
"AddressSet"
: [
{
"AddressId"
:
"eip-qy123abc"
,
"AddressName"
: null,
"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"
}
}
|
Code instructions :
1)Python rewrite PHP Code , There are some details , Such as int(time.time())、random.randint(1000, 1000000)、sorted(req_params_array) etc.
2) The parameters are arranged in ascending order xxx.split('&') —> sort($req_params_array) —> '&'.join(xxx)
3) Signature method , Need to add urllib.quote、base64.b64encode(xxx)、digest() etc. , Otherwise, you will often be prompted for wrong signature
req_signature = urllib.quote( base64.b64encode(hmac.new(req_secretkey, req_uri, digestmod=hashlib.sha256).digest()) ) # urllib.quote(xxx)
Python In the code , Special attention hmac Signature sha256 What we get after that is digest(), instead of hexdigest() If there is a mistake here, you will always be prompted for wrong signature !
In conclusion PHP and Python Correspondence of
1) PHP Signature
1
2
3
4
5
6
7
|
// sha1
$hmac_sha1_str
=
base64_encode
(hash_hmac(
"sha1"
,
$data
,
$secret_access_key
));
// HMAC-SHA1 encryption
$signature
= urlencode(
$hmac_sha1_str
);
// code URL
// sha256
$hmac_sha256_str
=
base64_encode
(hash_hmac(
"sha256"
,
$data
,
$secret_access_key
));
// HMAC-SHA256 encryption
$signature
= urlencode(
$hmac_sha256_str
);
// code URL
|
2)Python Signature
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( hmac.new(secret_access_key, data, digestmod
=
hashlib.sha1).digest() )
signature
=
urllib.quote(hmac_sha1_str)
# sha256
hmac_sha256_str
=
base64.b64encode( hmac.new(secret_access_key, data, digestmod
=
hashlib.sha256).digest() )
signature
=
urllib.quote(hmac_sha256_str)
# sha256
hmac_sha256_str
=
base64.b64encode( hmac.new(secret_access_key, data, digestmod
=
hashlib.sha256).hexdigest() )
# 16 Base number , error
signature
=
urllib.quote(hmac_sha256_str)
|