Python实现API接口签名调用的完整指南:HMAC-SHA256、JWT、RSA实例
在调用第三方API时,签名是保证请求身份真实性与数据完整性的关键步骤。服务端通过验证签名来判断请求是否合法、是否被篡改。本文将基于Python语言,从原理到代码,覆盖主流签名方式,并重点解析一种基于HMAC-SHA256的签名实现(类似WPS4风格),同时给出OAuth 2.0、JWT、RSA非对称签名和MD5参数签名的实战示例。1. 签名调用通用流程
无论采用何种算法,签名调用通常按以下步骤进行:
- 准备请求参数:包括业务参数(如文件ID、金额)、公共参数(如access_key、timestamp、nonce)。
- 按照API文档规定的规则(如排序、拼接、添加密钥)生成待签名字符串,并使用指定加密算法(如HMAC-SHA256、RSA-SHA256)计算签名。
- 将签名放入请求头(Header)或请求体中发送。
- 服务端收到请求后,用相同规则和密钥重新计算签名,比对一致则通过验证,否则返回4xx错误。
2. 基于HMAC-SHA256的请求签名实现(核心示例)
以下代码演示了一个完整的签名生成与HTTP请求发起过程。该实现源自类似WPS4的API签名规范,通用性好,可直接套用于其他要求HMAC-SHA256签名的接口。
import json
import requests
import hashlib
import time
import hmac
access_key = 'xxxxxxxxxxxxxxx'
secret_key = 'xxxxxxxxxxxxxxx'
def _wps4_sig(method, url, date, body):
print(body)
if body is None:
bodySha = ""
else:
bodySha = hashlib.sha256(body.encode('utf-8')).hexdigest()
content = "xxx-4" + method + url + "application/json" + date + bodySha
print(content)
signature = hmac.new(secret_key.encode('utf-8'), content.encode('utf-8'), hashlib.sha256).hexdigest()
return "xxx-4 %s:%s" % (access_key, signature)
def wps4_request(method, host, uri, body=None, cookie=None, headers=None):
requests.packages.urllib3.disable_warnings()
if body is not None and not isinstance(body, str):
body = json.dumps(body)
date = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
header = {"Content-type": "application/json"}
header['xxx-Docs-Date'] = date
header['xxx-Docs-Authorization'] = _wps4_sig(method, uri, date, body)
if headers is not None:
for key, value in headers.items():
header = value
url = "%s%s" % (host, uri)
r = requests.request(method, url, data=body, headers=header, cookies=cookie, verify=False)
return r.status_code, r.text
def edit(file_id=1):
uri = '/api/edit/v1/files/{0}/link?type=w'.format(file_id)
result = wps4_request('GET', 'http://xx.xx.xx.xxx:xxxx/open', uri)
print(result)
print(result)
if __name__ == '__main__':
edit()
关键点解释:
- _wps4_sig 函数将请求方法、URI、Content-Type、日期和请求体SHA256摘要拼接成字符串,再用HMAC-SHA256算法以secret_key为密钥计算签名。返回格式为“xxx-4 access_key:signature”。
- 日期必须按照RFC 1123格式生成,服务端会验证该时间戳,防止重放攻击。
- 请求体为空时 bodySha 置为空字符串,否则对body进行SHA256哈希。
- wps4_request 自动处理日期、签名头和请求发送,返回状态码和响应文本。
- 该签名方式适用于需要高安全级别的RESTful API调用,如办公套件、云存储等服务的接口。
3. 其他常见签名方式及Python实现
3.1 OAuth 2.0 客户端凭证模式
适用于服务器到服务器的授权(如Google、GitHub API)。
import requests
def get_oauth_token(client_id, client_secret, token_url):
data = {
'grant_type': 'client_credentials',
'client_id': client_id,
'client_secret': client_secret,
}
resp = requests.post(token_url, data=data)
return resp.json()['access_token']
# 获取 token 并调用
client_id = 'your_client_id'
client_secret = 'your_secret'
token_url = 'https://auth.example.com/token'
token = get_oauth_token(client_id, client_secret, token_url)
headers = {'Authorization': f'Bearer {token}'}
resp = requests.get('https://api.example.com/data', headers=headers)
注意:access_token有过期时间,需缓存并定期刷新。
3.2 JWT(JSON Web Token)
常用于用户登录态和微服务间认证。JWT自包含用户信息,无需服务端存储会话。
import jwt
import time
SECRET_KEY = 'your_secret_key'
payload = {
'user_id': 123,
'exp': int(time.time()) + 3600# 1小时后过期
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
headers = {'Authorization': f'Bearer {token}'}
resp = requests.get('https://api.example.com/protected', headers=headers)
JWT也可使用RS256(RSA)非对称算法,此时需要提供公私钥对。
3.3 RSA非对称签名(私钥签名,公钥验证)
适用于支付回调、银行接口等高安全场景。
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import base64
import requests
def sign_with_rsa(private_key_pem, message):
private_key = serialization.load_pem_private_key(private_key_pem, password=None)
signature = private_key.sign(
message.encode('utf-8'),
padding.PKCS1v15(),
hashes.SHA256()
)
return base64.b64encode(signature).decode('utf-8')
# 使用示例
with open('private_key.pem', 'rb') as f:
private_key = f.read()
message = 'GET /api/v1/resource'
signature = sign_with_rsa(private_key, message)
headers = {'X-Signature': signature, 'X-User': 'client_id'}
resp = requests.get('https://api.example.com/resource', headers=headers)
签名内容需严格按照API文档约定,可能是整个请求行或参数的摘要。
3.4 简单的MD5参数签名(老旧系统)
部分旧版接口仍使用此方式,安全性较低,建议尽快升级。
import hashlib
import requests
def md5_sign(params, salt):
raw = f"key1={params['key1']}&key2={params['key2']}&salt={salt}"
return hashlib.md5(raw.encode('utf-8')).hexdigest()
params = {'amount': 100, 'order_id': '123'}
params['sign'] = md5_sign(params, 'your_salt')
resp = requests.post('https://api.example.com/pay', data=params)
排序和拼接方式以API文档为准,通常按参数名顺序拼接。
4. 总结
本文从实际项目出发,展示了Python实现API接口签名的多种方法。核心示例基于HMAC-SHA256算法,通过拼接特定字符串并计算签名,可适配大多数RESTful服务。其他三种方式(OAuth 2.0、JWT、RSA、MD5)覆盖了从简单到高安全的典型场景。实际开发中,需仔细阅读API文档,明确签名规则、密钥获取方式以及过期机制。建议新系统优先使用HMAC-SHA256或RSA-SHA256,放弃MD5。掌握这些签名调用技巧,能极大提升开发效率和接口安全防护能力。
Re: Python实现API接口签名调用的完整指南:HMAC-SHA256、JWT、RSA实例
感谢楼主的分享,这份指南非常详尽,尤其是HMAC-SHA256签名的实现部分,从拼接规则到日期格式都写得很清楚,对实际开发很有帮助。不过帖子在OAuth 2.0部分好像被截断了,后面的JWT和RSA实例没看到,楼主方便补全一下吗?另外想请教一下,如果请求体是嵌套的JSON对象,SHA256是对整个字符串做哈希吗?期待后续内容!Re: Python实现API接口签名调用的完整指南:HMAC-SHA256、JWT、RSA实例
非常感谢楼主的分享,非常实用的教程!代码结构清晰,关键点解释也很到位,特别是HMAC-SHA256签名部分的拼接逻辑和日期格式化细节,对于新手来说很容易上手。想请教一下:如果请求体是二进制数据(比如上传文件),bodySha的计算是否需要特殊处理?另外,当前实现中似乎没有加入nonce随机数,是否计划在后续版本中增加这一层防重放机制?期待楼主更新JWT和RSA部分的完整示例!Re: Python实现API接口签名调用的完整指南:HMAC-SHA256、JWT、RSA实例
楼主的分享非常详细,HMAC-SHA256那段代码直接就能跑起来,很适合做通用签名模板。我在复制学习时发现一个小点:`wps4_request` 函数里自定义 headers 赋值那行 `header = value` 似乎应该是 `header = value`,不然会把整个字典覆盖掉,算是个笔误但容易踩坑。 另外想请教一下楼主的这个签名方案里有没有考虑 `nonce` 随机数?很多 API 除了时间戳还会加随机串防重放,如果用时间戳容差的话服务端一般设多少秒?期待后续 JWT 和 RSA 的部分补上,特别是 RSA 私钥签名、公钥验证的实战例子,企业换 key 时特别需要。
页:
[1]