AWS4 版本签名计算参考

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Time: 2021/7/24 8:12
# @Author:zhangmingda
# @File: api_for_aws4_signature.py
# @Software: PyCharm
# Description: from urllib.request import quote
import hashlib
import hmac
import datetime
import requests
import json
import base64 class KscClient(object):
def __init__(self, ak, sk,service, domain, region, use_ssl=False):
self.ak = ak
self.sk = sk
self.host = service + "." + domain
self.region = region
self.service = service
self.protocol = 'https' if use_ssl else 'http'
self.base_url = self.protocol + '://' + self.host + '/' # 创建规范化请求查询字符串方法
def generate_canonical_querystring(self, **params):
'''
:param params: 查询字符串字典
:return: url编码后的查询字符串key1=value1&key2=value2 ...
'''
sorted_params = ''
sorted_param_keys = sorted(params.keys())
for param in sorted_param_keys:
# print(param)
sorted_params += quote(param) + '=' + quote(params.get(param), safe='') + '&' # 查询字符串中的值任何字符串都进行URL编码
# print(sorted_params)
return sorted_params[:-1] # 生成标准化请求头,请求头大写转小写,排序返回字符串
def generate_canonical_headers(self, **headers):
'''
:param headers: 所有用来签名的请求头
:return: 返回小写请求头排序后的key:value 字符串,每个key:value 之间\n换行
'''
sorted_headers = '' # 准备标准请求头key+value字符串
sorted_signed_headers = '' # 准备签名的请求头key组合字符串
header_keys = headers.keys() # 获取请求头所有key
lower_headers = {} # 准备存放小写请求头和值的字典
for header in header_keys: # 把大写请求头字典都转换为小写请求头字典
lower_headers[header.lower()] = headers.get(header)
sorted_lower_header_keys = sorted(lower_headers.keys()) # 把签名的请求头排序 '''排序后的请求头和值进行组合字符串'''
for lower_header in sorted_lower_header_keys:
sorted_headers += lower_header + ':' + str(lower_headers[lower_header]).strip() + '\n'
sorted_signed_headers += lower_header + ";"
# print("============请求头排序==============")
# print(sorted_headers)
# print('------被签名的请求头----')
# print(sorted_signed_headers)
# print("==========请求头排序end============")
sorted_lower_headers = {
'sorted_headers': sorted_headers, # 签名的请求头key 和 value
'signed_headers': sorted_signed_headers[:-1] # 被签名的请求头字符串组合,最后一个分号; 不要
}
return sorted_lower_headers # 十六进制请求体Sha256Hash值--->请求体用
def bytes_data_sha256_hex(self, bytes_data=''.encode()):
'''
:param binary_data: 字节码文件
:return: 返回请求体内容的sha256 哈希值
'''
sha256 = hashlib.sha256()
sha256.update(bytes_data)
return sha256.hexdigest().lower() # 构建被签名字符串,把标准请求canonical_request 哈希取16进制用
def str_sha256_hex(self, string=''):
'''
:param string:
:return: 字符串的sha256哈希值
'''
sha256 = hashlib.sha256()
sha256.update(string.encode())
return sha256.hexdigest() # UTC时间字符串工具
def get_utc_datetime(self):
now_utc = datetime.datetime.utcnow()
datetime_utc = now_utc.strftime('%Y%m%dT%H%M%SZ')
date_utc = now_utc.strftime('%Y%m%d')
return datetime_utc, date_utc # 生成规范化请求的字符串方法
def generate_canonical_request(self, method, encode_uri, canonical_querystring, canonical_headers, signed_headers,payload_sha256_hex):
''' 1.1 规范化请求CanonicalRequest计算方法'''
return method + '\n' \
+ encode_uri + '\n' \
+ canonical_querystring + '\n' \
+ canonical_headers + '\n' \
+ signed_headers + '\n' \
+ payload_sha256_hex # 请求体不参与签名 时 : + 'UNSIGNED-PAYLOAD' # 生成被签名字符串的方法
def generate_string_tosign(self, algorithm, datetime_utc, credentialscope, canonical_reques_sha256_hex ):
''' 1.2 被签名字符串计算方法'''
return algorithm + '\n' \
+ datetime_utc + '\n' \
+ credentialscope + '\n' \
+ canonical_reques_sha256_hex # 第二步构建签名key的工具方法
def encode_string_to_hmac_256_digest(self, encode_salt, msg, digestmod=hashlib.sha256):
'''
:param encode_salt: 盐
:param msg: 字符串信息
:param digestmod: 摘要算法
:return: HMAC-SHA256 加盐哈希后的字节
'''
digest_maker = hmac.new(encode_salt, msg.encode(), digestmod=digestmod)
return digest_maker.digest() # 创建签名KEY的方法
def generate_signing_key(self, signature_version,sk, date_utc, region, service, termchar='aws4_request'):
k_secret = signature_version + sk
k_date = self.encode_string_to_hmac_256_digest(k_secret.encode(), date_utc)
k_region = self.encode_string_to_hmac_256_digest(k_date, region)
k_service = self.encode_string_to_hmac_256_digest(k_region, service)
k_signing = self.encode_string_to_hmac_256_digest(k_service, termchar)
return k_signing # 创建签名的方法
def generate_signature(self, signing_key, string_tosign):
digest_maker = hmac.new(signing_key, string_tosign.encode(), digestmod=hashlib.sha256)
hex_signature = digest_maker.hexdigest()
# print('hex_signature:', digest_maker.hexdigest())
return hex_signature # 构建带签名的请求头,或签名url查询字符串
def get_auth_data(self, method, query_params, append_headers={}, binary_payload=''.encode()):
# ========================================1. 创建被签名字符串======================================
# 1.1 构建标准化请求
method = method # 1.1.1 HTTP方法
canonical_uri = '/' # 1.1.2 资源URI
encode_uri = quote(canonical_uri, safe="/") # 1.1.2 将URI编码成%字符串格式 不包含? 后的url查询参数
payload_sha256_hex = self.bytes_data_sha256_hex(binary_payload) # 1.1.5 请求体sha256 十六进制HASH值
datetime_utc, date_utc = self.get_utc_datetime()
# 准备请求头
signature_headers = {
'Host': self.host,
'X-amz-date': datetime_utc
}
signature_headers.update(append_headers)
# 请求头排序格式化
sorted_lower_headers = self.generate_canonical_headers(**signature_headers)
canonical_headers = sorted_lower_headers.get('sorted_headers') # 1.1.4 小写排序后的请求头key:value
signed_headers = sorted_lower_headers.get('signed_headers') # 1.1.5 小写排序后的签名头
# 1.2 创建信任状
credentialscope = date_utc + "/" + self.region + "/" + self.service + "/aws4_request"
# 查询参数字典
auth_params = {}
# 签名放在URL中时计算签名传递参数
if query_params:
auth_params = {
'X-Amz-Algorithm': "AWS4-HMAC-SHA256",
'X-Amz-Credential': self.ak + '/' + credentialscope,
'X-Amz-Date': datetime_utc,
'X-Amz-SignedHeaders': signed_headers,
}
auth_params.update(query_params)
# print('auth_params: ', auth_params)
auth_in_header_canonical_querystring = self.generate_canonical_querystring(**query_params) # 1.1.3 通过header传递签名的查询字符串
auth_in_queryparam_canonical_querystring = self.generate_canonical_querystring(**auth_params) # 1.1.3 通过URL传递签名的查询字符串
canonical_request_auth_in_header = self.generate_canonical_request(method, encode_uri, auth_in_header_canonical_querystring, canonical_headers, signed_headers, payload_sha256_hex)
canonical_request_auth_in_url = self.generate_canonical_request(method, encode_uri, auth_in_queryparam_canonical_querystring, canonical_headers, signed_headers, payload_sha256_hex)
print("Header传递签名的规范化请求".center(50, "="))
print(canonical_request_auth_in_header)
print("canonical_request_auth_in_url".center(50, "*"))
print(canonical_request_auth_in_header)
print("规范化化请求done".center(50, "=")) # 1.2 创建被签名字的符串StringToSign
canonical_request_auth_in_header_sha256_hex = self.str_sha256_hex(canonical_request_auth_in_header) # 规范化请求的256哈希值
canonical_request_auth_in_url_sha256_hex = self.str_sha256_hex(canonical_request_auth_in_url) # 规范化请求的256哈希值
algorithm = 'AWS4-HMAC-SHA256'
string_tosign_auth_in_header = self.generate_string_tosign(algorithm, datetime_utc, credentialscope, canonical_request_auth_in_header_sha256_hex)
string_tosign_auth_in_url = self.generate_string_tosign(algorithm, datetime_utc, credentialscope, canonical_request_auth_in_url_sha256_hex) print('Header传递签名被签名的字符串'.center(50, '='))
print(string_tosign_auth_in_header)
print('URL传递签名被签名的字符串'.center(50, '*'))
print(string_tosign_auth_in_url)
print('被签名的字符串Done!'.center(50,'=')) # ========================================2. 创建签名 ======================================
# 2.1创建签名签名秘钥
signature_version = 'AWS4'
signing_key = self.generate_signing_key(signature_version, self.sk, date_utc, self.region, self.service)
print("签名秘钥:",signing_key)
# 2.2 创建签名
signature_for_header = self.generate_signature(signing_key, string_tosign_auth_in_header)
signature_for_url = self.generate_signature(signing_key, string_tosign_auth_in_url)
print('Header鉴权的签名:', signature_for_header)
print('url鉴权的签名:', signature_for_url)
# ========================================3 请求头或URL 传递签名鉴权和参数 ======================================
authorization_headers = {
'Authorization': "AWS4-HMAC-SHA256 Credential="
+ self.ak + '/'
+ credentialscope + ", "
+ "SignedHeaders="
+ signed_headers + ', '
+ 'Signature=' + signature_for_header,
}
# 3.1请求头携带签名,返回带签名的请求头
authorization_headers.update(signature_headers) # 3.2 url携带签名返回带签名的URL查询字符串
request_query_params = {
'X-Amz-Signature': signature_for_url
}
request_query_params.update(auth_params)
authorization_params = self.generate_canonical_querystring(**request_query_params)
# print('request_query_params: ', request_query_params)
# print('authorization_params:',authorization_params)
auth_data = {
'authorization_headers': authorization_headers,
'authorization_params': request_query_params,
'signature_headers': signature_headers, # get object 在URL里面传递签名 请求头要带的签名头
}
return auth_data # 通过标准请求头方式传递签名GET文件
def get_test_auth_in_header(self, query_params={}, append_headers={}):
method = 'GET' # 1.1.1 HTTP方法
auth_data = self.get_auth_data(method, query_params, append_headers)
authorization_headers = auth_data.get('authorization_headers')
req = requests.get(url=self.base_url, headers=authorization_headers, params=query_params)
print('Header鉴权的URL:', req.url)
print(req.status_code)
print(req.text) def get_test_auth_in_query_param(self,query_params={}, append_headers={}):
method = 'GET' # 1.1.1 HTTP方法
auth_data = self.get_auth_data(method, query_params, append_headers)
auth_query_params = auth_data.get('authorization_params')
signature_headers = auth_data.get('signature_headers')
canonical_querystring = self.generate_canonical_querystring(**auth_query_params) # 通过URL传递鉴权=requests 传参方式1
url_for_auth = self.base_url + "?" + canonical_querystring
req2 = requests.get(url=url_for_auth, headers=signature_headers)
print("手工拼接鉴权的URL:", url_for_auth)
print(req2.status_code)
print(req2.text)
# 通过URL传递鉴权=requests 传参方式2
req3 = requests.get(self.base_url, headers=signature_headers, params=auth_query_params)
# req3 = requests.get(url=self.base_url, headers=signature_headers, params=canonical_querystring)
print("requests自动拼接鉴权的URL:", req3.url)
print(req3.status_code)
print(req3.text) if __name__ == '__main__':
ak = 'XXXXXXXXXXXXXXX'
sk = 'XXXXXXXXXXXXXXXXXXXXXXXXX'
service = 'kcm'
domain = 'api.ksyun.com'
region = 'cn-beijing-6'
ksc = KscClient(ak, sk, service, domain, region)
query_params = {
'Action': 'GetDownloadLink',
'Version': '2016-03-04',
'CertificateId': 'kcm2021022216204501'
}
ksc.get_test_auth_in_header(query_params=query_params)
# ksc.get_test_auth_in_query_param(query_params=query_params)

Header 传递鉴权测试

URL传递鉴权测试

Python 计算AWS4签名,Header鉴权与URL鉴权的更多相关文章

  1. python 计算校验和

    校验和是经常使用的,这里简单的列了一个针对按字节计算累加和的代码片段.其实,这种累加和的计算,将字节翻译为无符号整数和带符号整数,结果是一样的. 使用python计算校验和时记住做截断就可以了. 这里 ...

  2. [转载] python 计算字符串长度

    本文转载自: http://www.sharejs.com/codes/python/4843 python 计算字符串长度,一个中文算两个字符,先转换成utf8,然后通过计算utf8的长度和len函 ...

  3. Python计算斗牛游戏的概率

    Python计算斗牛游戏的概率 过年回家,都会约上亲朋好友聚聚会,会上经常会打麻将,斗地主,斗牛.在这些游戏中,斗牛是最受欢迎的,因为可以很多人一起玩,而且没有技术含量,都是看运气(专业术语是概率). ...

  4. 利用Python计算π的值,并显示进度条

    利用Python计算π的值,并显示进度条  第一步:下载tqdm 第二步;编写代码 from math import * from tqdm import tqdm from time import ...

  5. 用Python计算幂的两种方法,非递归和递归法

    用Python计算幂的两种方法: #coding:utf-8 #计算幂的两种方法.py #1.常规方法利用函数 #不使用递归计算幂的方法 """ def power(x, ...

  6. Python计算分位数

    Python计算分位数    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/gdkyxy2013/article/details/80911514 ...

  7. python 怎么模拟加header(如User-Agent、Content-Type等等)

    # -*- coding: cp936 -*- #python 27 #xiaodeng #python 怎么模拟加header(如User-Agent.Content-Type等等) #办法一: i ...

  8. 为了用python计算一个汉字的中心点,差点没绞尽脑汁活活累死

    为了用python计算一个汉字的中心点,差点没绞尽脑汁活活累死

  9. python计算时间差的方法

    本文实例讲述了python计算时间差的方法.分享给大家供大家参考.具体分析如下: 1.问题: 给定你两个日期,如何计算这两个日期之间间隔几天,几个星期,几个月,几年? 2.解决方法: 标准模块date ...

随机推荐

  1. 学习 DDD 之消化知识!

    接触到DDD到现在已经有8个月份了,目前所维护的项目也是基于DDD的思想开发的,从一开始的无从下手,到现在游刃有余,学到不少东西,但是都是一些关键字和零散的知识,同时我也感受到了是因为我对项目越来越熟 ...

  2. 洛谷 P5332 - [JSOI2019]精准预测(2-SAT+bitset+分块处理)

    洛谷题面传送门 七月份(7.31)做的题了,题解到现在才补,不愧是 tzc 首先不难发现题目中涉及的变量都是布尔型变量,因此可以考虑 2-SAT,具体来说,我们将每个人在每个时刻的可能的状态表示出来. ...

  3. 洛谷 P5280 - [ZJOI2019]线段树(线段树+dp,神仙题)

    题面传送门 神仙 ZJOI,不会做啊不会做/kk Sooke:"这八成是考场上最可做的题",由此可见 ZJOI 之毒瘤. 首先有一个非常显然的转化,就是题目中的"将线段树 ...

  4. DirectX12 3D 游戏开发与实战第十章内容(上)

    仅供个人学习使用,请勿转载.谢谢! 10.混合 本章将研究混合技术,混合技术可以让我们将当前需要光栅化的像素(也称为源像素)和之前已经光栅化到后台缓冲区的像素(也称为目标像素)进行融合.因此,该技术可 ...

  5. nginx——网站显示问题

    一般来说修改3个位置,一个是nginx.h.另一个是ngx_http_header_filter_module.c.还有一个ngx_http_special_response.c. 提示:一般修改都是 ...

  6. kafka的安装及使用

    前言花絮 今天听了kafka开发成员之一的饶军老师的讲座,讲述了kafka的前生今世.干货的东西倒是没那么容易整理出来,还得刷一遍视频整理,不过两个比较八卦的问题,倒是很容易记住了. Q:为什么kaf ...

  7. ubuntu终端ls颜色配置

    buntu中没有LS_COLORS,/etc/目录中也没有DIR_COLORS,所以这里使用dircolor命令加以解决 1. 利用dircolors命令,查看我们的系统当前的文件名称显示颜色的值,然 ...

  8. 也谈string.Join和StringBuilder的性能比较

    前几天在园子里面看到一篇讲StringBuilder性能的文章.文章里面给出了一个测试用例,比较StringBuilder.AppendJoin和String.Join的性能.根据该测试结果,&quo ...

  9. C/C++ Qt StringListModel 字符串列表映射组件

    StringListModel 字符串列表映射组件,该组件用于处理字符串与列表框组件中数据的转换,通常该组件会配合ListView组件一起使用,例如将ListView组件与Model模型绑定,当Lis ...

  10. Windows zip版本安装MySQL

    Windows --MySQL zip版本安装记录: step1. 官网download zip包:http://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5. ...