整体说明
本实验,将会通过 Python 语言,以云服务器 > 查询地域列表为例,进行签名,鉴权的简单实现,同时进行测试,最终获得到预期结果。 请在操作本实验之前,自己提前获取好密钥信息,并且替换掉本文中的测试密钥。
必备环境和工具
请确保已经安装了 Python 等。 可以通过:
python3 --version
或者:
python --version
来看一下 python 的版本。
准备密钥
通过网页:https://console.cloud.tencent.com/capi 获得秘钥信息(SecretId和SecretKey) 例如我的:
SecretId:
AKIDGRSHz3e17HVaVEeEWddR4Wr1zmNld5yk
SecretKey:
rY5VmsobGoBM2YsFWcXG0c3HMI2f6OVU
SecretId 用于标识 API 调用者身份 SecretKey 用于加密签名字符串和服务器端验证签名字符串的密钥。 用户必须严格保管安全凭证,避免泄露。 API 密钥是构建腾讯云 API 请求的重要凭证,使用腾讯云 API 可以操作您名下的所有腾讯云资源,为了您的财产和服务安全,请妥善保存和定期更换密钥,当您更换密钥后,请及时删除旧密钥。
签名理论实现
任务时间:时间未知
获得参数信息
- 以云服务器 CVM 查询地域列表为例,获取他的参数信息:
参数名 | 是否必填 | 参数类型 |
---|---|---|
Action | 是 | String |
Version | 是 | String |
Region | 否 | String |
- 获得公共参数部分:
参数名 | 是否必填 | 参数类型 |
---|---|---|
Action | 是 | String |
Region | 是 | String |
Timestamp | 是 | Integer |
Nonce | 是 | Integer |
SecretId | 是 | String |
Signature | 是 | String |
Version | 是 | String |
SignatureMethod | 否 | String |
Token | 否 | String |
- 删除掉非必须填写参数、重复参数,和目标参数:
参数名 | 是否必填 | 参数类型 |
---|---|---|
Action | 是 | String |
Version | 是 | String |
Timestamp | 是 | Integer |
Nonce | 是 | Integer |
SecretId | 是 | String |
进行参数排序:
首先对所有请求参数按参数名做字典序升序排列,所谓字典序升序排列,直观上就如同在字典中排列单词一样排序,按照字母表或数字表里递增顺序的排列次序,即先考虑第一个“字母”,在相同的情况下考虑第二个“字母”,依此类推。用户可以借助编程语言中的相关排序函数来实现这一功能,如php中的ksort函数。上述示例参数的排序结果如下:
参数名 | 是否必填 | 参数类型 |
---|---|---|
Action | 是 | String |
Nonce | 是 | Integer |
SecretId | 是 | String |
Timestamp | 是 | Integer |
Version | 是 | String |
字典形式:
{
'Action' : 'DescribeRegions’,
'Nonce' : 11886,
'SecretId' : 'AKIDGRSHz3e17HVaVEeEWddR4Wr1zmNld5yk',
'Timestamp' : 1465185768,
'Version' : '2017-03-12',
}
组成字符串
- 此步骤生成请求字符串。 将把上一步排序好的请求参数格式化成“参数名称”=“参数值”的形式,如对 Action 参数,其参数名称为"Action",参数值为"DescribeInstances",因此格式化后就为 Action=DescribeInstances 。 注意:“参数值”为原始值而非url编码后的值。
Action=DescribeRegions&
Nonce=11886&
SecretId=AKIDGRSHz3e17HVaVEeEWddR4Wr1zmNld5yk&
Timestamp=1465185768
Version=2017-03-12&
- 此步骤生成签名原文字符串。 签名原文字符串由以下几个参数构成:
-
请求方法: 支持 POST 和 GET 方式,这里使用 GET 请求,注意方法为全大写。
-
请求主机:查看实例列表(DescribeInstances)的请求域名为:cvm.tencentcloudapi.com。实际的请求域名根据接口所属模块的不同而不同,详见各接口说明。
-
请求路径: 当前版本云 API 的请求路径固定为 / 。
-
请求字符串: 即上一步生成的请求字符串。
签名原文串的拼接规则为:
请求方法 + 请求主机 +请求路径 + ? + 请求字符串
GETcvm.tencentcloudapi.com/?Action=DescribeRegions&Nonce=11886&SecretId=AKIDGRSHz3e17HVaVEeEWddR4Wr1zmNld5yk&Timestamp=1465185768&Version=2017-03-12
加密生成签名串
此步骤生成签名串。 首先使用 HMAC-SHA1 算法对上一步中获得的签名原文字符串进行签名,然后将生成的签名串使用 Base64 进行编码,即可获得最终的签名串。
签名代码实现
任务时间:时间未知
建立文件
vim demo_1.py
输入密钥信息
例如: 请注意将密钥信息修改成自己的!
SecretId = "AKIDGRSHz3e17HVaVEeEWddR4Wr1zmNld5yk"
SecretKey = "rY5VmsobGoBM2YsFWcXG0c3HMI2f6OVU"
填写必须信息
import time
uri = "cvm.tencentcloudapi.com"
paramDict = {
"Action":"DescribeRegions",
"Version":"2017-03-12",
"SecretId":SecretId,
"Nonce":123456,
"Timestamp":int(time.time()),
}
排序
tempList = []
tempDict = {}
for eveKey, eveValue in paramDict.items():
tempLowerData = eveKey.lower()
tempList.append(tempLowerData)
tempDict[tempLowerData] = eveKey
tempList.sort()
resultList = []
for eveData in tempList:
tempStr = str(tempDict[eveData]) + "=" + str(paramDict[tempDict[eveData]])
resultList.append(tempStr)
第一次字符串拼接
sourceStr = "&".join(resultList)
第二次字符串拼接
requestStr = "%s%s%s%s%s"%("GET", uri, "/", "?", sourceStr)
SHA1 加密
import sys
if sys.version_info[0] > 2:
signStr = requestStr.encode("utf-8")
SecretKey = SecretKey.encode("utf-8")
import hashlib
digestmod = hashlib.sha1
import hmac
hashed = hmac.new(SecretKey, signStr, digestmod)
Base64编码
import binascii
base64Data = binascii.b2a_base64(hashed.digest())[:-1]
if sys.version_info[0] > 2:
base64Data = base64Data.decode()
GET请求还需要URL编码
import urllib.parse
base64Data = urllib.parse.quote(base64Data)
对签名结果测试
任务时间:时间未知
生成请求url
url = "https://" + uri + "/" + "?" + sourceStr + "&Signature=" + base64Data
发起请求,并将结果变成Json格式
import urllib.request
import json
for eveData in json.loads(urllib.request.urlopen(url).read().decode("utf-8"))["Response"]["RegionSet"]:
print(eveData)
保存上面的文件
- 完整代码如下:
请注意将密钥信息修改成自己的!
SecretId = "AKIDGRSHz3e17HVaVEeEWddR4Wr1zmNld5yk"
SecretKey = "rY5VmsobGoBM2YsFWcXG0c3HMI2f6OVU"
'''
Timestamp Integer 是 当前 UNIX 时间戳,可记录发起 API 请求的时间。例如1529223702,如果与当前时间相差过大,会引起签名过期错误。
Nonce Integer 是 随机正整数,与 Timestamp 联合起来,用于防止重放攻击。
SecretId String 是 在云API密钥上申请的标识身份的 SecretId,一个 SecretId 对应唯一的 SecretKey ,而 SecretKey 会用来生成请求签名 Signature。
Action 是 String 公共参数,本接口取值:DescribeRegions
Version 是 String 公共参数,本接口取值:2017-03-12
'''
import time
uri = "cvm.tencentcloudapi.com"
paramDict = {
"Action":"DescribeRegions",
"Version":"2017-03-12",
"SecretId":SecretId,
"Nonce":123456,
"Timestamp":int(time.time()),
}
tempList = []
tempDict = {}
for eveKey, eveValue in paramDict.items():
tempLowerData = eveKey.lower()
tempList.append(tempLowerData)
tempDict[tempLowerData] = eveKey
tempList.sort()
resultList = []
for eveData in tempList:
tempStr = str(tempDict[eveData]) + "=" + str(paramDict[tempDict[eveData]])
resultList.append(tempStr)
sourceStr = "&".join(resultList)
requestStr = "%s%s%s%s%s"%("GET", uri, "/", "?", sourceStr)
import sys
if sys.version_info[0] > 2:
signStr = requestStr.encode("utf-8")
SecretKey = SecretKey.encode("utf-8")
import hashlib
digestmod = hashlib.sha1
import hmac
hashed = hmac.new(SecretKey, signStr, digestmod)
import binascii
base64Data = binascii.b2a_base64(hashed.digest())[:-1]
if sys.version_info[0] > 2:
base64Data = base64Data.decode()
import urllib.parse
base64Data = urllib.parse.quote(base64Data)
url = "https://" + uri + "/" + "?" + sourceStr + "&Signature=" + base64Data
print(url)
import urllib.request
import json
for eveData in json.loads(urllib.request.urlopen(url).read().decode("utf-8"))["Response"]["RegionSet"]:
print(eveData)
- 保存文件:
:wq
- 运行获得结果:
python3 demo_1.py
- 结果:
至此,我们完成了签名过程,并进行了相关的验证。
网友评论