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)

print

(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)