Ali SDK API 相关
2018/11/19 Chenxin
基础知识(SDK,API Explorer)
SDK API 区别
SDK更新肯定要慢些,需要阿里云给出升级的SDK才可以使用.SDK是API的一种实现方式而已.
API更新会比较及时,因为无需打包成SDK发布给用户.只需要更新阿里云服务器端接收数据解析,以及对应的文档说明即可.SDK应该也是解析成API后发起到阿里云的调用.
SDK简单的示例代码(入门推荐)
阿里云SDK各版本对应服务说明(不同服务都有一个SDK) https://develop.aliyun.com/tools/sdk?spm=a2c1g.8271268.10000.5.77a3df25JZvIkF#/python
阿里云SDK python 简易使用说明 https://help.aliyun.com/document_detail/53090.html?spm=a2c1g.8271268.10000.7.3f04df25RQ8QeL
SDK完整的示例代码即 阿里云 API Explorer,其自动生成的SDK代码,是阿里云推荐访问API的方式,而非用户手动的认证和签名.
OpenApi 使用(对应SDK)说明,在线通过已登录用户调用API.给出对应SDK使用代码,以及线上调用后的返回结果.
https://api.aliyun.com/?spm=a2c1g.8271268.10000.2.3f04df25RQ8QeL
SDK 的使用
比如-获取实例信息
使用OpenApi上自动生成的参考SDK代码示例方式(推荐,因为这个比较方便使用.直接在阿里提供的网站上就会自动生成)
从OpenApi上(https://api.aliyun.com/?spm=a2c1g.8271268.10000.2.3f04df25RQ8QeL),可以自动生成的SDK代码,如下:
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
client = AcsClient(‘LTAI3b9Wpey0U0cc‘, ‘kFV8tfHBKesPC1gMnglbxAdEygPys2‘, ‘cn-shenzhen‘) # 这里是keyid和secretkey
request = CommonRequest()
request.set_accept_format(‘json‘)
request.set_domain(‘ecs.aliyuncs.com‘)
request.set_method(‘POST‘)
request.set_version(‘2014-05-26‘)
request.set_action_name(‘DescribeInstances‘)
request.add_query_param(‘RegionId‘, ‘cn-shenzhen‘)
response = client.do_action_with_exception(request)
python2: print(response)
print(str(response, encoding = ‘utf-8‘))
使用SDK说明文档里的那个示例方式(不推荐,因为需要自己去挨个摸索)
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkecs.request.v20140526 import DescribeInstancesRequest
from aliyunsdkecs.request.v20140526 import StopInstanceRequest
创建AcsClient实例
client = AcsClient(
"LTAI3b9Wpey0U0cc", # 这里是密钥
"kFV8tfHBKesPC1gMnglbxAdEygPys2",
"cn-shenzhen"
)
创建request,并设置参数
request = DescribeInstancesRequest.DescribeInstancesRequest()
request.set_PageSize(10)
发起API请求并显示返回值
try:
response = client.do_action_with_exception(request)
print(response)
print(dir(response))
except ServerException as e:
print(e)
except ClientException as e:
print(e)
API使用-签名认证
基本说明
如果需要各个服务的API HTTP方式调用,则需要到文档各个服务里(比如ECS里)去查看API文档,里面有对应的HTTP请求格式.
比如ECS API方式请求(格式,参数,签名)-API- 请求结构说明
阿里云 API 签名机制的 Python 实现原理
参考
https://www.jianshu.com/p/7574349a5042 python2.X版本
https://help.aliyun.com/document_detail/27149.html?spm=a2c4g.11186623.6.639.39ce47d0ygIKdh 文档最下方,"附:python2.X版本签名机制代码示例"
基本步骤
- 构造规范化的请求字符串 (Canonicalized Query String)
- 构造被签名字符串 StringToSign
- 计算 HMAC 值
- 计算签名值
- 添加签名
其他说明
访问的URL不需要排序.
构造待签名字符串 StringToSign 是需要按照ASCII码排序(顺序若与服务器端不同,生成的签名也会不同).
比如获取实例状态信息URL
通过阿里云API explorer(阿里云提供的网页) 方式获得参考(顺序可以随机)
http://ecs.aliyuncs.com/
?
AccessKeyId=TMP.AQHo...npKl0HsZrE # 自动生成的一个临时keyid
&Action=DescribeInstances
&Format=JSON
&RegionId=cn-shenzhen
&SecureTransport=true
&SignatureMethod=HMAC-SHA1
&SignatureNonce=386b2187986d4855c0efc08a985ff98c
&SignatureVersion=1.0
&SourceIp=118.112.75.132
&Timestamp=2018-11-19T07%3A44%3A22Z
&Version=2014-05-26
&Signature=O7ZnC7FzlGfjAMpD38RdkPRZSvw%3D
手动python创建的
https://ecs.aliyuncs.com/
?SignatureVersion=1.0
&Format=JSON
&TimeStamp=2018-11-21T08%3A28%3A17Z
&RegionId=cn-shenzhen
&AccessKeyId=LTAI3b9Wpey0U0cc
&SignatureMethod=HMAC-SHA1
&Version=2014-05-26
&Signature=YdudjAGoUKNkMP3KzPL9tSabqok%3D
&Action=DescribeInstances
&SignatureNonce=65512030-ed67-11e8-be20-8b2f931290aa
除了 Signature 之外,其它的参数都比较容易获得,有些甚至是固定的值,具体可以参考阿里云文档.
公共请求参数
请求中所需要的公共参数为:
AccessKeyId # 账号密钥 ID
Format # 返回消息的格式化方式,JSON or XML 默认值为 XML
SignatureMethod # 签名方式,目前为 HMAC-SHA1
SignatureNonce # 唯一随机数,防止网络攻击。不同请求间使用不同的随机数。
SignatureVersion # 签名算法版本,目前为 1.0
Timestamp # 请求的时间戳,UTC时间,例如: 2013-01-10T12:00:00Z
Version # 版本号,为日期形式,例如: 2014-05-26 每个产品不同
Signature # 最难搞定的签名(不属于公共参数)
接口参数
除了公共参数之外,还需要具体接口(Action)的请求参数.每个 Action 接口的参数可以参考对应产品的接口文档,如Action=DescribeInstances
签名
Signature 是基于公共参数和接口参数的,所以比较复杂。
具体实现
Signature 具体代码实现
1构造规范化请求字符串 (Canonicalized Query String)
构造 dict
D = {
‘Format‘:‘JSON‘,
‘Version‘:‘2014-05-26‘,
‘SignatureMethod‘:‘HMAC-SHA1‘
}
排序
由于签名要求唯一性,包括顺序,所以需要按照参数名称排序
sortedD = sorted(D.items(), key=lambda x: x[0])
sortedD
[(‘Format‘, ‘JSON‘),(‘SignatureMethod‘, ‘HMAC-SHA1‘),(‘Version‘, ‘2014-05-26‘)]
先通过 D.items() 转化为 List, 然后利用 sorted 方式按照 key 排序
URL 编码
由于在标准请求字符串中需要使用 UTF-8 字符集,对请求参数名称和值中有些不符合规范的字符要进行 url 编码,具体规则为:
字符 AZ、az、0~9 以及字符“-”、“_”、“.”、“~”不编码;
其它字符编码成 %XY 的格式,其中 XY 是字符对应 ASCII 码的 16 进制表示。比如英文的双引号(”)对应的编码为 %22;
对于扩展的 UTF-8 字符,编码成 %XY%ZA… 的格式;
英文空格( )要编码成 %20,而不是加号(+)。
注意:一般支持URL编码的库(比如 Java 中的 java.net.URLEncoder)都是按照 “application/x-www-form-urlencoded”的 MIME 类型的规则进行编码的。实现时可以直接使用这类方式进行编码,把编码后的字符串中加号(+)替换成 %20、星号(*)替换成 %2A、%7E 替换回波浪号(~),即可得到上述规则描述的编码字符串。
这里使用 python 中的 urllib 库来进行编码:
def percentEncode(str):
res = urllib.quote(str.decode(sys.stdin.encoding).encode(‘utf8‘), ‘‘)
res = res.replace(‘+‘, ‘%20‘)
res = res.replace(‘*‘, ‘%2A‘)
res = res.replace(‘%7E‘, ‘~‘)
return res
这里构造一个编码函数,对一个字符串进行编码,返回编码后的字符串
生成规范化请求字符串CanonicalizedQueryString
canstring = ‘‘
for k,v in sortedD:
canstring += ‘&‘ + percentEncode(k) + ‘=‘ + percentEncode(v)canstring
‘&Format=JSON&SignatureMethod=HMAC-SHA1&Version=2014-05-26‘ #这里的Canonicalized Query String 是包含&符号的(&没有参与percentEncode)
2构造待签名字符串 StringToSign
规则为:
StringToSign=
HTTPMethod + “&” +
percentEncode(“/”) + ”&” +
percentEncode(CanonicalizedQueryString)
所以在这个实例中
stringToSign = ‘GET&%2F&‘ + percentEncode(canstring[1:]) #canstring[1:]防止&符号重复; percentEncode(“/”) -> %2F
stringToSign
‘GET&%2F&Format%3DJSON%26SignatureMethod%3DHMAC-SHA1%26Version%3D2014-05-26‘ #注意,这里除GET外,其他参数需要按照ASCII码排序
3计算 HMAC 值
access_key_secret = ‘access_key_secret‘
h = hmac.new(access_key_secret + "&", stringToSign, sha1) # 标准要求加密用的密钥是"原密钥+&"作为加密的key
h
<hmac.HMAC instance at 0x35ed440>
4计算签名值
signature = base64.encodestring(h.digest()).strip()
signature
‘sq8LVH+ZItZiVQ0/rVnHV1kP/BE=‘
到此生成了 signature 签名
5添加签名
D[‘Signature‘] = signature
D
{‘Format‘: ‘JSON‘,
‘Signature‘: ‘sq8LVH+ZItZiVQ0/rVnHV1kP/BE=‘,
‘SignatureMethod‘: ‘HMAC-SHA1‘,
‘Version‘: ‘2014-05-26‘}
所以在这个实例中,最终请求的 url 为url = ‘http://ecs.aliyuncs.com/?‘ + urllib.urlencode(D)
url
‘http://ecs.aliyuncs.com/?SignatureMethod=HMAC-SHA1&Version=2014-05-26&Signature=sq8LVH%2BZItZiVQ0%2FrVnHV1kP%2FBE%3D&Format=JSON‘
拿到浏览器直接访问即可,得到结果为:
{"Message":"The input parameter "Action" that is mandatory for processing this request is not supplied.","RequestId":"129880D4-710D-4D2C-9F8B-12777FA1D3C6","HostId":"ecs.aliyuncs.com","Code":"MissingParameter"}
由于是测试环境,就给了三个参数,所以还少很多参数,正常来说把这些参数都加上,然后生成 signature,组成 url 后直接访问就可以得到结果。
最终签名程序
python3.6版本(1为写死的方式,2为配置文件及命令行方式)
1写死密钥与调用固定API DescribeInstancesRequest-api-py3.py
!/usr/bin/env python
-- coding:utf-8 --
"""
File Name: DescribeInstancesRequest-api-py3.py
Description:
Author: chenxin
date: 2018/11/19 18:10
"""
该脚本适用于python3.x版本
import sys
import urllib.parse
import urllib.request
import base64
import hmac
from hashlib import sha1
import time
import uuid
access_key_id = ‘LTAI3b9Wpey0U0cc‘
access_key_secret = ‘kFV8tfHBKesPC1gMnglbxAdEygPys2‘
定义endpoint终端节点地址(服务节点)
handle_server_address = ‘https://ecs.aliyuncs.com‘
对 URL 进行编码
def percent_encode(string):
res = urllib.parse.quote(string.encode(sys.stdin.encoding, ‘utf8‘), ‘‘)
res = res.replace(‘+‘, ‘%20‘)
res = res.replace(‘*‘, ‘%2A‘)
res = res.replace(‘%7E‘, ‘~‘)
return res
计算签名
def compute_signature(parameters, access_key_secret2):
# 先排序,生成一个list.签名值是根据所有参数ascii值排序后生成的字符串计算来的.
sorted_parameters = sorted(parameters.items(), key=lambda x: x[0])
# 生成规范化的请求字符串canonicalized_query_string.
canonicalized_query_string = ‘‘
for (k, v) in sorted_parameters:
canonicalized_query_string += ‘&‘ + percent_encode(k) + ‘=‘ + percent_encode(v)
# 构造待签名字符串 string_to_sign.这里从[1:]开始,因为从0开始,会变成GET&%2F&&Action=...多了一个"&"符号
string_to_sign = ‘GET&%2F&‘ + percent_encode(canonicalized_query_string[1:])
# 计算签名时,RFC2104规定的Key值是你的 AccessKeySecret 并加上与号&,其ASCII值为38.
# python3直接使用str模式的话,会报TypeError: key: expected bytes or bytearray, but got ‘str‘错误.故先转换为bytes.
access_key_secret_bytes = bytes(access_key_secret2, ‘utf-8‘)
and_sign_bytes = bytes("&", ‘utf-8‘)
string_to_sign_bytes = bytes(string_to_sign, ‘utf-8‘)
h = hmac.new(access_key_secret_bytes + and_sign_bytes, string_to_sign_bytes, sha1)
signature = base64.encodebytes(h.digest()).strip()
return signature
构造整体url地址
def compose_url():
timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
parameters = {
‘Format‘: ‘JSON‘,
‘Version‘: ‘2014-05-26‘,
‘AccessKeyId‘: access_key_id,
‘SignatureVersion‘: ‘1.0‘,
‘SignatureMethod‘: ‘HMAC-SHA1‘,
‘SignatureNonce‘: str(uuid.uuid1()),
‘TimeStamp‘: timestamp,
‘Action‘: ‘DescribeInstances‘, # 接口参数
‘RegionId‘: ‘cn-shenzhen‘, # 接口参数
}
# 计算签名.参数access_key_secret是个全局参数
signature = compute_signature(parameters, access_key_secret)
# 将签名参数植入parameters字典
parameters[‘Signature‘] = signature
# 构造最终访问url地址.当前parameters字典里包含了公共请求参数+接口参数+签名
url = handle_server_address + "/?" + urllib.parse.urlencode(parameters)
return url
if name == ‘main‘:
# 获取URL地址
url_address = compose_url()
print(url_address)
# 访问API接口,并返回相关结果
return_info = urllib.request.urlopen(url_address).read()
# 解决中文乱码
return_info_utf8 = return_info.decode(‘UTF-8‘)
print(return_info_utf8)
2带密钥配置文件与命令调用(对应服务API)方式 signature-auth-py3.py
!/usr/bin/env python
-- coding:utf-8 --
"""
File Name: signature_auth_py3.py
Description:
Author: chenxin
date: 2018/11/22 10:59
"""
使用方法:
1把accesskey+accesssecet放到aliyun.ini
2执行python xxx.py Action=xxx B=yyy C=zzz
3其他接口都一样,看一下文档,传参数即可
python signature_auth.py DescribeInstances RegionId=cn-shenzhen
python signature_auth.py Action=DescribeInstances RegionId=cn-shenzhen
python signature_auth.py Action=DescribeInstanceStatus RegionId=cn-shenzhen
import sys
import os
import urllib.parse
import urllib.request
import base64
import hmac
from hashlib import sha1
import time
import uuid
from optparse import OptionParser
import configparser
import traceback
公共变量
access_key_id = ‘‘
access_key_secret = ‘‘
定义终端节点地址(服务节点)
handle_server_address = ‘https://ecs.aliyuncs.com‘
配置文件,非windows系统为‘/aliyun.ini‘
CONFIGFILE = os.getcwd() + ‘\aliyun.ini‘
[Credentials] 是配置文件中的一个章节
CONFIGSECTION = ‘Credentials‘
cmdlist = ‘‘‘接口说明请参考线上文档‘‘‘
对 URL 进行编码
def percent_encode(str):
res = urllib.parse.quote(str.encode(sys.stdin.encoding, ‘utf8‘), ‘‘)
res = res.replace(‘+‘, ‘%20‘)
res = res.replace(‘*‘, ‘%2A‘)
res = res.replace(‘%7E‘, ‘~‘)
return res
计算签名
def compute_signature(parameters, access_key_secret):
# 先排序,生成一个list.签名值是根据所有参数ascii值排序后生成的字符串计算来的.
sorted_parameters = sorted(parameters.items(), key=lambda parameters: parameters[0])
# 生成规范化的请求字符串canonicalized_query_string.
canonicalized_query_string = ‘‘
for (k, v) in sorted_parameters:
canonicalized_query_string += ‘&‘ + percent_encode(k) + ‘=‘ + percent_encode(v)
# 构造待签名字符串 string_to_sign.这里从[1:]开始,因为从0开始,会变成GET&%2F&&Action=...多了一个"&"符号
string_to_sign = ‘GET&%2F&‘ + percent_encode(canonicalized_query_string[1:])
# 计算签名时,RFC2104规定的Key值是你的 AccessKeySecret 并加上与号&,其ASCII值为38.
# python3直接使用str模式的话,会报TypeError: key: expected bytes or bytearray, but got ‘str‘错误.故先转换为bytes.
access_key_secret_bytes = bytes(access_key_secret, ‘utf-8‘)
and_sign_bytes = bytes("&", ‘utf-8‘)
string_to_sign_bytes = bytes(string_to_sign, ‘utf-8‘)
h = hmac.new(access_key_secret_bytes + and_sign_bytes, string_to_sign_bytes, sha1)
signature = base64.encodebytes(h.digest()).strip()
# python2.7使用以下.
# h = hmac.new(access_key_secret + "&", string_to_sign, sha1)
# signature = base64.encodestring(h.digest()).strip()
return signature
构造整体url地址
def compose_url(user_params):
timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
parameters = {
‘Format‘: ‘JSON‘,
‘Version‘: ‘2014-05-26‘,
‘AccessKeyId‘: access_key_id,
‘SignatureVersion‘: ‘1.0‘,
‘SignatureMethod‘: ‘HMAC-SHA1‘,
‘SignatureNonce‘: str(uuid.uuid1()),
‘TimeStamp‘: timestamp,
}
# 将用户手动输入的参数装入parameters字典.这样parameters中保存着所有参数(含公共参数,接口参数,暂时不含签名参数)
for key in user_params.keys():
parameters[key] = user_params[key]
# 计算签名.参数access_key_secret是个全局参数
signature = compute_signature(parameters, access_key_secret)
# 将签名参数植入parameters字典
parameters[‘Signature‘] = signature
# 构造最终访问url地址.当前parameters字典里包含了公共请求参数+接口参数+签名
url = handle_server_address + "/?" + urllib.parse.urlencode(parameters)
return url
xxx.py调用命令中含密钥配置文件的路径的话(自定义路径),执行写入操作
def configure_accesskeypair(args, options):
if options.accesskeyid is None or options.accesskeysecret is None:
print("config miss parameters, use --id=[accesskeyid] --secret=[accesskeysecret]")
sys.exit(1)
config = configparser.RawConfigParser()
config.add_section(CONFIGSECTION)
config.set(CONFIGSECTION, ‘accesskeyid‘, options.accesskeyid)
config.set(CONFIGSECTION, ‘accesskeysecret‘, options.accesskeysecret)
cfgfile = open(CONFIGFILE, ‘w+‘)
config.write(cfgfile)
cfgfile.close()
xxx.py 调用命令中第一个参数不是密钥配置路径的话,则执行默认的认证步骤,如下
def setup_credentials():
config = configparser.ConfigParser()
try:
# 读取配置文件
config.read(CONFIGFILE)
global access_key_id
global access_key_secret
# 获取CONFIGSECTION章节中对应的字段
access_key_id = config.get(CONFIGSECTION, ‘accesskeyid‘)
access_key_secret = config.get(CONFIGSECTION, ‘accesskeysecret‘)
except Exception as e:
print(traceback.format_exc())
print(e)
print("can‘t get access key pair, use config --id=[accesskeyid] --secret=[accesskeysecret] to setup")
sys.exit(1)
if name == ‘main‘:
# 制作帮助信息
parser = OptionParser("%s Action=action Param1=Value1 Param2=Value2\n" % sys.argv[0])
parser.add_option("-i", "--id", dest="accesskeyid", help="specify access key id")
parser.add_option("-s", "--secret", dest="accesskeysecret", help="specify access key secret")
(options, args) = parser.parse_args()
if len(args) < 1:
parser.print_help()
sys.exit(0)
if args[0] == ‘help‘:
print(cmdlist)
sys.exit(0)
if args[0] != ‘config‘:
setup_credentials()
else:
configure_accesskeypair(args, options)
sys.exit(0)
user_params = {} # 用来保存用户手动调用时给出的参数
idx = 1
# 如果第一个参数不是以Action=开头的话,则将第一个参数全部赋值给user_params[‘action‘],以便适应python signature_auth.py DescribeInstanceStatus方式调用.
# 这里Action,RegionId等,可以全部小写的,URL调用中不敏感.
if not sys.argv[1].lower().startswith(‘action=‘):
user_params[‘action‘] = sys.argv[1]
idx = 2
for arg in sys.argv[idx:]:
try:
key, value = arg.split(‘=‘)
user_params[key.strip()] = value # .strip()默认删除空白符(包括‘\n‘, ‘\r‘, ‘\t‘, ‘ ‘)
except ValueError as e:
# print(e.read().strip())
print(e)
raise SystemExit(e)
# 获取最终访问URL地址
url_address = compose_url(user_params)
print(url_address)
return_info = urllib.request.urlopen(url_address).read()
# 因当前使用的是windows控制台调用的python,所以需要匹配系统编码.否则阿里云返回的中文信息会乱码.
type = sys.getfilesystemencoding()
return_info_gbk = return_info.decode(‘UTF-8‘)
print(return_info_gbk)
python2.7版本
signature-auth-py2.py
!/usr/bin/python
-- coding:utf-8 --
"""
File Name:
Description:
Author: chenxin
date: 2018/11/21 17:56
"""
使用方法:
1把accesskey+accesssecet放到aliyun.ini
2执行python xxx.py Action=xxx B=yyy C=zzz
3其他接口都一样,看一下文档,传参数即可
python signature_auth.py DescribeInstances RegionId=cn-shenzhen
python signature_auth.py Action=DescribeInstances RegionId=cn-shenzhen
python signature_auth.py Action=DescribeInstanceStatus RegionId=cn-shenzhen
import sys, os
import urllib, urllib2
import base64
import hmac
import hashlib
from hashlib import sha1
import time
import uuid
import json
from optparse import OptionParser
import ConfigParser
import traceback
access_key_id = ‘‘;
access_key_secret = ‘‘;
cdn_server_address = ‘https://cdn.aliyuncs.com‘
cdn_server_address = ‘https://ecs.aliyuncs.com‘
CONFIGFILE = os.getcwd() + ‘\aliyun.ini‘
CONFIGSECTION = ‘Credentials‘
cmdlist = ‘‘‘接口说明请参照pdf文档‘‘‘
将 URL 进行编码
def percent_encode(str):
res = urllib.quote(str.decode(sys.stdin.encoding).encode(‘utf8‘), ‘‘)
res = res.replace(‘+‘, ‘%20‘)
res = res.replace(‘*‘, ‘%2A‘)
res = res.replace(‘%7E‘, ‘~‘)
return res
计算签名
def compute_signature(parameters, access_key_secret):
#先排序,生成一个list.签名值是根据所有参数ascii值排序后生成的字符串计算来的.
sortedParameters = sorted(parameters.items(), key=lambda parameters: parameters[0])
#生成规范化的请求字符串canonicalizedQueryString.
canonicalizedQueryString = ‘‘
for (k, v) in sortedParameters:
canonicalizedQueryString += ‘&‘ + percent_encode(k) + ‘=‘ + percent_encode(v)
#构造待签名字符串 StringToSign.这里从[1:]开始,因为从0开始,会变成GET&%2F&&Action=...多了一个"&"符号
stringToSign = ‘GET&%2F&‘ + percent_encode(canonicalizedQueryString[1:])
#计算签名时,RFC2104规定的Key值是你的 AccessKeySecret 并加上与号&,其ASCII值为38.
h = hmac.new(access_key_secret + "&", stringToSign, sha1)
signature = base64.encodestring(h.digest()).strip()
return signature
def compose_url(user_params):
timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
parameters = {
‘Format‘: ‘JSON‘,
‘Version‘: ‘2014-05-26‘,
‘AccessKeyId‘: access_key_id,
‘SignatureVersion‘: ‘1.0‘,
‘SignatureMethod‘: ‘HMAC-SHA1‘,
‘SignatureNonce‘: str(uuid.uuid1()),
‘TimeStamp‘: timestamp,
}
#将用户手动输入的参数装入parameters字典.这样parameters中保存着所有参数(含公共参数,接口参数,暂时不含签名参数)
for key in user_params.keys():
parameters[key] = user_params[key]
#计算签名.参数access_key_secret是个全局参数
signature = compute_signature(parameters, access_key_secret)
#将签名参数植入parameters字典
parameters[‘Signature‘] = signature
#构造最终访问url地址.当前parameters字典里包含了公共请求参数+接口参数+签名
url = cdn_server_address + "/?" + urllib.urlencode(parameters)
return url
def make_request(user_params, quiet=False):
url = compose_url(user_params)
# print url
return url
def configure_accesskeypair(args, options):
if options.accesskeyid is None or options.accesskeysecret is None:
print("config miss parameters, use --id=[accesskeyid] --secret=[accesskeysecret]")
sys.exit(1)
config = ConfigParser.RawConfigParser()
config.add_section(CONFIGSECTION)
config.set(CONFIGSECTION, ‘accesskeyid‘, options.accesskeyid)
config.set(CONFIGSECTION, ‘accesskeysecret‘, options.accesskeysecret)
cfgfile = open(CONFIGFILE, ‘w+‘)
config.write(cfgfile)
cfgfile.close()
def setup_credentials():
config = ConfigParser.ConfigParser()
try:
config.read(CONFIGFILE)
global access_key_id
global access_key_secret
access_key_id = config.get(CONFIGSECTION, ‘accesskeyid‘)
access_key_secret = config.get(CONFIGSECTION, ‘accesskeysecret‘)
except Exception, e:
print traceback.format_exc()
print("can‘t get access key pair, use config --id=[accesskeyid] --secret=[accesskeysecret] to setup")
sys.exit(1)
if name == ‘main‘:
#制作-h --help信息
parser = OptionParser("%s Action=action Param1=Value1 Param2=Value2\n" % sys.argv[0])
parser.add_option("-i", "--id", dest="accesskeyid", help="specify access key id")
parser.add_option("-s", "--secret", dest="accesskeysecret", help="specify access key secret")
(options, args) = parser.parse_args()
if len(args) < 1:
parser.print_help()
sys.exit(0)
if args[0] == ‘help‘:
print cmdlist
sys.exit(0)
if args[0] != ‘config‘:
setup_credentials()
else: # it‘s a configure id/secret command
configure_accesskeypair(args, options)
sys.exit(0)
user_params = {} #用来保存用户手动调用时给出的参数
idx = 1
#如果第一个参数不是以Action=开头的话,则将第一个参数全部赋值给user_params[‘action‘],以便适应python signature.py DescribeInstanceStatus方式调用.
#这里Action,RegionId等,可以全部小写的,URL调用中不敏感.
if not sys.argv[1].lower().startswith(‘action=‘):
user_params[‘action‘] = sys.argv[1]
idx = 2
for arg in sys.argv[idx:]:
try:
key, value = arg.split(‘=‘)
user_params[key.strip()] = value #.strip()默认删除空白符(包括‘\n‘, ‘\r‘, ‘\t‘, ‘ ‘)
except ValueError, e:
print(e.read().strip())
raise SystemExit(e)
# 获取最终访问URL地址
url_address = make_request(user_params)
return_info = urllib.urlopen(url_address).read()
# 因当前使用的是windows控制台调用的python,所以需要匹配系统编码.否则阿里云返回的中文信息会乱码.
type = sys.getfilesystemencoding()
return_info_gbk = return_info.decode(‘UTF-8‘).encode(type)
print return_info_gbk
补充知识
HMAC说明
HMAC的一个典型应用是用在“质疑/应答”(Challenge/Response)身份认证中。
认证流程
(1) 先由客户端向服务器发出一个验证请求。
(2) 服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为质疑)。
(3) 客户端将收到的随机数提供给ePass,由ePass使用该随机数与存储在ePass中的密钥进行HMAC-MD5运算并得到一个结果作为认证证据传给服务器(此为响应)。
(4) 与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-MD5运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户
在这个过程中,可能遭到安全攻击的是服务器发送的随机值和用户发送的hmac结果,而对于截获了这两个值的黑客而言这两个值是没有意义的,绝无获取用户密码的可能性,随机值的引入使hmac只在当前会话中有效,大大增强了安全性和实用性。