python实现阿里云Signature签名计算

遇到的问题

以前工作中写脚本访问阿里云的资源时,都是通过调用系统命令(调用CLI工具)的方式,这次尝试通过http请求来实现想要的操作。
本次实现中遇到的问题:
1、向api发送请求是总是返回报错:Specified parameter Version is not valid,从报错上看是参数中设置的Version的值有问题,但反复核实请求中带的Version并没有问题。
解决方法:如果你遇到同样的问题,估计跟我一样,构建好请求url后,在向api发送请求时也是以调用系统命令(curl)的方式来实现的,这里要把请求的url用引号引起来,形式如下:cmd = "curl ‘http://xxx.example.com?Aciton=XXXX&…’ ",具体为什,据说是因为url中的&符号,是一个命令行执行后台挂起的标志,导致curl命令执行与预期不符,我并没有去验证,大体上应该就是这么回事了
2、在解决了上一个问题后,再次发送请求,返回结果为:errorCode:IncompleteSignature,msg:“The request signature does not conform to Aliyun standards.”
解决方法:报错很明显是计算得到的签名Signature有问题,问题出在待签名字符串上,待签名字符串中的参数部分,我只对它进行了一次urlencode操作,还需要再进行一次percentEncode操作,将其中的等号“=”,编码成%3D

签名代码实现

下面记录一下代码的实现,学过的东西还是要多复习,毕竟编码经验还不纯熟。(我安装的是python3.7的版本)
用法:aliyunTool.py -f params.json
params.json示例:

{
        "endpoint": "https://ecs.aliyuncs.com",
        "AccessKeyId": "xxxxxxxxxxxxxxxxxxxxxxx",
        "AccessKeySecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "Params": {
            "AccessKeyId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "Format": "json",
            "Version": "2014-05-26",
            "SignatureMethod": "HMAC-SHA1",
            "Timestamp": "",
            "SignatureVersion": "1.0",
            "SignatureNonce": "",
            "Action": "DescribeInstances",
            "RegionId": "cn-beijing",
            "PageSize": "50"
        }
    }

代码示例,复制可直接使用:

import datetime
import urllib.request
import urllib.parse
import hmac
import base64
import json
import uuid
import argparse
import copy
def getConfigFromFile(configFile):
    config_file = open(configFile)
    config = json.load(config_file)
    config_file.close()
    # 计算时间戳参数,使用的是utc时间,并格式化成指定的格式
    return config

def  requestByConfig(config):
    #计算时间戳参数,使用的是utc时间,并格式化成指定的格式
    timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
    #下面三个参数要求全局唯一,使用uuid生成随机字符串
    #ClientToken = str(uuid.uuid4()) #本示例中用不到
    #Token = str(uuid.uuid4()) #本示例中用不到
    signatureNonce = str(uuid.uuid4())

    #下面根据阿里云文档计算待签名字符串
    #def generateToSignStr(commonparams,customparams):
    #首先合并公共参数和自定义参数,然后排序
    params = copy.copy(config["Params"])
    params["Timestamp"] = timestamp
    params["SignatureNonce"] = signatureNonce
    sortedParams = sorted(params.items(), key=lambda x: x[0])
    #然后对合并排序后的参数进行urlencode编码,得到的是多个key=value的键值对通过&符号连接后组成的字符串
    urlencodeParams = urllib.parse.urlencode(sortedParams).replace("+","%20").replace("*","%2A").replace("%7E","~")
    #再处理一次,将urlencode后的字符串中的“=”和“&”进行percent编码
    urlencodeParams = urllib.parse.quote_plus(urlencodeParams)
    #最后生成待签名字符串
    toSignStr = "GET"+"&"+urllib.parse.quote_plus("/")+"&"+urlencodeParams
    #计算签名
    h = hmac.new((config["AccessKeySecret"]+"&").encode(),toSignStr.encode(),"sha1")
    signature = base64.encodebytes(h.digest()).strip().decode()

    #将Signature添加到请求参数,生成请求url
    params["Signature"] = signature
    url = config["endpoint"]+"?"+urllib.parse.urlencode(params).replace("+","%20")
    print(url)
#发送请求并打印结果
    res=None
    try:
        response = urllib.request.urlopen(url)
        # 先将结果转换成字典,再转换成json对象,格式化输出
        res = json.load(response)
#        print(json.dumps(res, sort_keys=True, indent=2))
        return res
    except IOError as e:
        print(e.read())
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-f", "--conf", type=str, default="config.json", help="请求接口的配置及参数的配置文件")
    args = parser.parse_args()
    conf = getConfigFromFile(args.conf)
    x = requestByConfig(conf)
    print(x)

    params = {
        "endpoint": "https://ecs.aliyuncs.com",
        "AccessKeyId": "xxxxxxxxxxxxxxxxxxxxxxx",
        "AccessKeySecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "Params": {
            "AccessKeyId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "Format": "json",
            "Version": "2014-05-26",
            "SignatureMethod": "HMAC-SHA1",
            "Timestamp": "",
            "SignatureVersion": "1.0",
            "SignatureNonce": "",
            "Action": "DescribeInstances",
            "RegionId": "cn-beijing",
            "PageSize": "50"
        }
    }
    
    y = requestByConfig(params)
    print(y)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值