要使用AWS签名v4对AWS IoT的HTTP请求进行签名,您可以按照以下步骤执行:
pip install boto3 requests
import boto3
import requests
from requests.auth import AuthBase
class AWSRequestSigner(AuthBase):
def __init__(self, session, service):
self._credentials = session.get_credentials()
self._region = session.region_name or 'us-east-1'
self._service = service
def __call__(self, request):
# 获取当前时间和日期
amz_date = request.headers['X-Amz-Date']
# 创建签名
signature = self._get_signature(request, amz_date)
# 添加认证头部
request.headers['Authorization'] = signature
return request
def _get_signature(self, request, amz_date):
# 获取要签名的信息
canonical_request = self._get_canonical_request(request)
string_to_sign = self._get_string_to_sign(amz_date, canonical_request)
signing_key = self._get_signing_key(amz_date)
# 使用签名密钥计算签名值
signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
# 构建认证头部
credential_scope = '{}/{}/{}/aws4_request'.format(amz_date[:8], self._region, self._service)
authorization_header = 'AWS4-HMAC-SHA256 Credential={}/{}, SignedHeaders={}, Signature={}'.format(
self._credentials.access_key, credential_scope, self._get_signed_headers(request), signature)
return authorization_header
def _get_canonical_request(self, request):
# 构建规范请求字符串
canonical_request = '{}\n{}\n{}\n{}\n{}\n{}'.format(
request.method,
self._get_canonical_uri(request),
self._get_canonical_query_string(request),
self._get_canonical_headers(request),
self._get_signed_headers(request),
hashlib.sha256(request.body).hexdigest())
return canonical_request
def _get_string_to_sign(self, amz_date, canonical_request):
# 构建要签名的字符串
string_to_sign = 'AWS4-HMAC-SHA256\n{}\n{}\n{}'.format(
amz_date,
self._get_credential_scope(amz_date),
hashlib.sha256(canonical_request.encode('utf-8')).hexdigest())
return string_to_sign
def _get_signing_key(self, amz_date):
# 计算签名密钥
date_key = self._sign('AWS4' + self._credentials.secret_key, amz_date[:8])
region_key = self._sign(date_key, self._region)
service_key = self._sign(region_key, self._service)
signing_key = self._sign(service_key, 'aws4_request')
return signing_key
def _sign(self, key, value):
return hmac.new(key.encode('utf-8'), value.encode('utf-8'), hashlib.sha256).digest()
def _get_canonical_uri(self, request):
# 获取规范URI
uri = request.path_url
if uri == '/':
return '/'
else:
return quote(uri, safe='')
def _get_canonical_query_string(self, request):
# 获取规范查询字符串
query_params = request.url.split('?')[1:]
query_params.sort()
return '&'.join(query_params)
def _get_canonical_headers(self, request):
# 获取规范头部
headers = {k.lower(): v.strip() for k, v in request.headers.items()}
sorted_headers = sorted(headers.items())
return '\n'.join(['{}:{}'.format(k, v) for k, v in sorted_headers])
def _get_signed_headers(self, request):
# 获取签名的头部
headers = {k.lower() for k in request.headers.keys()}
return ';'.join(sorted(headers))
def _get_credential_scope(self, amz_date):
# 获取凭证范围
return '{}/{}/{}/aws4_request'.format(amz_date[:8], self._region, self._service)