跳到主要内容
接口鉴权与传输安全:签名、AK/SK、JWT 及加密方案 | 极客日志
Python SaaS WeChat Pay java 算法
接口鉴权与传输安全:签名、AK/SK、JWT 及加密方案 综述由AI生成 综述了接口鉴权与传输安全的核心机制。内容涵盖基于签名的鉴权(HMAC、AK/SK)、基于凭证的鉴权(API Key、JWT、OAuth 2.0、Basic Auth)以及传输保护(AES、RSA 加密)。文章通过 Python 示例演示了各方案的实现细节,并提供了针对不同场景(如 Web 前后端、车机端云、云对云)的选型建议,帮助开发者构建安全的 API 交互体系。
MqEngine 发布于 2026/3/28 更新于 2026/6/7 46 浏览一、为什么需要接口鉴权
接口一旦对外开放,如果没有鉴权,谁都可以调,带来的不仅是越权访问,还有身份冒充 、参数被篡改 、同一请求被重放 等问题。所以接口鉴权本质上要回答三件事:谁在调 、请求有没有被改过 、是不是旧请求重放 。本文先帮你把「鉴权」和「传输保护」区分开,再给一张总览表,然后按基于签名的鉴权 、基于凭证与标准的鉴权 、**传输保护(加解密)**三条线往下讲,顺带覆盖 Web 前后端、车机端云、云对云、A2A 等场景下怎么选型。
二、鉴权与传输安全:如何区分与总览
先把两个概念捋清楚,后面看各种手段就不会混:
鉴权 :解决「谁在调用」—— 靠签名、AK/SK、API Key、JWT、OAuth 2.0、Basic 等手段做身份与请求合法性校验。
传输保护 :解决「内容不被窃听或篡改」—— 通常和鉴权一起用,用对称/非对称加解密或 HTTPS 保证传输安全。
下面这张表按「鉴权 vs 传输保护」、典型场景和落地产品做了总览,方便你按场景对号入座。
类型 手段 典型场景 落地产品/场景示例 复杂度 安全性 鉴权 API Key 内部/开放平台简单鉴权 Stripe、SendGrid、多数 SaaS 控制台 API 低 中 鉴权 签名(如 HMAC) 开放 API、防篡改 微信支付/支付宝开放平台、部分银行/支付回调 中 高 鉴权 AK/SK 云厂商 API 阿里云、AWS、腾讯云、华为云、七牛对象存储 中 高 鉴权 JWT 无状态会话、微服务 前后端分离登录态、Auth0、Spring Security、很多 B 端后台 中 中高 鉴权 OAuth 2.0 第三方授权、开放平台 微信/QQ/微博登录、GitHub 授权、企业微信/飞书开放平台 高 高 鉴权 Basic / Digest 传统 HTTP 认证 内网监控/运维接口、部分老旧企业系统、路由器/摄像头管理 低 低/中 传输保护 对称/非对称加解密 敏感字段或报文加密 银企直连、支付报文、部分政务/医疗接口 中高 高
可以简单记:鉴权管「谁在调」,传输保护管「传得安不安全」;两者可以组合用,比如先鉴权再对 body 做加密。
三、基于签名的鉴权
这里讲两种:通用 HMAC 签名 (自建 API 或开放平台很常见)和 AK/SK (云厂商那套规范请求 + 签名)。本质都是「拿密钥对请求做签名、服务端用同一规则验签」,差别主要在于:请求要不要按云厂商的规范拼成「规范请求串」。
3.1 签名(HMAC)
做法是:把请求参数(一般会带上 timestamp、nonce)按约定规则排序、拼接成字符串,用 Secret 做 (或 MD5)得到签名,请求时把签名一起带上;服务端用同一个 Secret 按同样规则算一遍,和传上来的签名比对,一致就通过。timestamp 还可以用来做简单的防重放(例如只接受 5 分钟内的请求)。
HMAC-SHA256
服务端 -> 客户端:构造参数并排序
客户端 -> 服务端:拼接 HMAC-SHA256 (Secret, 参数字符串)
客户端 -> 服务端:请求 + Header 中带 signature/timestamp
服务端 -> 客户端:用同一 Secret 重算签名
服务端 -> 客户端:比对签名并校验时间
结果:200 或 401
Python 示例(仅用标准库,无需 pip install):
import hmac
import hashlib
import secrets
import time
from urllib.parse import urlencode
SECRET = secrets.token_bytes(32 )
def make_signature (params: dict ) -> str :
"""
生成签名:参数按 key 排序 → 拼成 key1=val1&key2=val2 → 对该串做 HMAC-SHA256。
注意:签名时不要包含 signature 自身,否则服务端无法复现。
"""
sorted_params = sorted (params.items())
sign_str = urlencode(sorted_params)
sig = hmac.new(SECRET, sign_str.encode(), hashlib.sha256).hexdigest()
return sig
params = {
"name" : "test" ,
"timestamp" : str (int (time.time())),
"nonce" : secrets.token_hex(8 ),
}
params["signature" ] = make_signature(params)
print ("客户端签名结果:" , params["signature" ])
def verify_signature (params: dict ) -> bool :
"""从参数中取出客户端传来的签名,用剩余参数重算,一致则通过。"""
received = params.pop("signature" , None )
if not received:
return False
expected = make_signature(params)
return hmac.compare_digest(received, expected)
params_for_verify = {
"name" : "test" ,
"timestamp" : params["timestamp" ],
"nonce" : params["nonce" ],
"signature" : params["signature" ],
}
print ("验签通过:" , verify_signature(params_for_verify))
3.2 AK/SK(Access Key / Secret Key) 和上面「签名」的思路一样,都是拿密钥对请求做 HMAC;区别在于云厂商会把 Method、URI、Query、Header、Body 等按固定规则拼成「规范请求串」,再据此生成「签名字符串」,最后用 Secret Key 算出签名,塞进 Authorization(一般带 AccessKey、SignedHeaders、Signature)。阿里云、AWS、腾讯云等开放 API 都是这一套。
Method+URI -> 规范请求串 -> 签名字符串 -> HMAC-SK 得 Signature -> Authorization Header
import hmac
import hashlib
import secrets
ACCESS_KEY = "AK" + secrets.token_hex(16 )
SECRET_KEY = secrets.token_urlsafe(32 )
def canonical_request (method: str , path: str , query: str , body: str ) -> str :
"""
拼出「规范请求串」,云厂商会严格规定格式(如每行顺序、Header 列表等)。
这里简化成:Method + Path + Query + Body 的 SHA256,实际需对照文档。
"""
body_hash = hashlib.sha256((body or "" ).encode()).hexdigest()
return f"{method} \n{path} \n{query} \n{body_hash} "
def sign (secret_key: str , string_to_sign: str ) -> str :
"""对「签名字符串」做 HMAC-SHA256,得到最终签名。"""
return hmac.new(
secret_key.encode(), string_to_sign.encode(), hashlib.sha256
).hexdigest()
method, path, query, body = "GET" , "/api/resource" , "a=1&b=2" , ""
canon = canonical_request(method, path, query, body)
signature = sign(SECRET_KEY, canon)
auth_header = f"AK {ACCESS_KEY} :{signature} "
print ("Authorization:" , auth_header)
四、基于凭证与标准的鉴权 这类方式不靠「对请求体做 HMAC」,而是用事先发下去的凭证 (API Key、JWT)或标准协议 (OAuth 2.0、Basic Auth)来做身份和权限校验,常见于前后端分离、第三方登录、服务调服务等场景。
4.1 API Key 在 Header(如 X-API-Key)或 Query 里带一个固定 Key,服务端在库或配置里查一下是否存在、是否有效即可。实现简单,适合内部或开放平台的低敏感接口。
同步请求示例(pip install requests):
import requests
import secrets
API_KEY = "sk-" + secrets.token_urlsafe(24 )
resp = requests.get("https://api.example.com/data" , headers={"X-API-Key" : API_KEY})
异步请求示例(适合高并发、异步框架内调用,pip install httpx):
import httpx
async def fetch_with_api_key (url: str , api_key: str ) -> dict :
"""在异步场景下用 httpx 发请求,不阻塞事件循环。"""
async with httpx.AsyncClient() as client:
resp = await client.get(url, headers={"X-API-Key" : api_key})
resp.raise_for_status()
return resp.json()
服务端:从 request.headers.get("X-API-Key") 取出 key,在数据库或配置中查是否存在、是否过期或禁用。
4.2 JWT(JSON Web Token) 无状态:登录成功后服务端签发一个 Token(由 Header.Payload.Signature 三部分组成),客户端之后每次请求在 Authorization 里带上;服务端用同一 Secret(或公钥)验签并解析 Payload 里的用户 ID、过期时间等,无需查库即可完成鉴权。
Header . Payload . Signature
Python 示例(pip install pyjwt):
import jwt
import secrets
import time
SECRET = secrets.token_hex(32 )
payload = {
"sub" : "user123" ,
"exp" : int (time.time()) + 3600 ,
}
token = jwt.encode(payload, SECRET, algorithm="HS256" )
print ("签发 Token:" , token)
decoded = jwt.decode(token, SECRET, algorithms=["HS256" ])
print ("解析出的 Payload:" , decoded)
4.3 OAuth 2.0(客户端凭证示例) 「客户端凭证」模式适合服务调服务 、无用户参与:用 client_id + client_secret 向授权服务器换一张 access_token,之后访问资源接口时在 Authorization 里带 Bearer <token> 即可。
资源接口 <- 授权服务 <- 客户端
client_id + client_secret -> access_token -> Authorization: Bearer access_token -> 资源
同步获取 Token 并调用资源接口(pip install requests):
import requests
def get_token (token_url: str , client_id: str , client_secret: str ) -> str :
"""向授权服务器用 client 身份换 access_token。"""
r = requests.post(
token_url,
data={
"grant_type" : "client_credentials" ,
"client_id" : client_id,
"client_secret" : client_secret,
},
headers={"Content-Type" : "application/x-www-form-urlencoded" },
)
r.raise_for_status()
return r.json()["access_token" ]
异步获取 Token 并调用(pip install httpx):
import httpx
async def get_token_async (token_url: str , client_id: str , client_secret: str ) -> str :
"""异步请求 token 端点,适合在 asyncio / FastAPI 等异步环境中使用。"""
async with httpx.AsyncClient() as client:
r = await client.post(
token_url,
data={
"grant_type" : "client_credentials" ,
"client_id" : client_id,
"client_secret" : client_secret,
},
headers={"Content-Type" : "application/x-www-form-urlencoded" },
)
r.raise_for_status()
return r.json()["access_token" ]
4.4 Basic Auth 把 username:password 做 Base64 编码,放到 Authorization: Basic <base64> 里。实现简单,但密码每次请求都会带上去,必须配合 HTTPS 使用。
import base64
def basic_header (username: str , password: str ) -> str :
"""拼出 Authorization: Basic xxx,注意仅编码不加密,务必走 HTTPS。"""
raw = f"{username} :{password} "
b64 = base64.b64encode(raw.encode()).decode()
return f"Basic {b64} "
五、传输保护:加密与解密 鉴权只管「谁在调」;真要防窃听、防篡改,还要靠传输保护 。对请求/响应体或敏感字段做加密时,常用对称加密(AES)或非对称加密(RSA) ,或者两者结合:用 RSA 加密一个随机的 AES 密钥,再用 AES 加密正文(混合加密),和前面任意一种鉴权方式搭配即可。
明文 -> AES 加密 -> 密文 -> 传输 -> AES 解密 -> 明文
Python 示例(pip install cryptography):
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.asymmetric import rsa, padding as rsa_padding
from cryptography.hazmat.primitives import hashes
import os
def aes_encrypt (key: bytes , plaintext: str ) -> bytes :
"""CBC 模式需要 IV,这里把 IV 拼在密文前 16 字节,解密时先取出再解。"""
iv = os.urandom(16 )
padder = padding.PKCS7(128 ).padder()
padded = padder.update(plaintext.encode()) + padder.finalize()
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
enc = cipher.encryptor().update(padded) + cipher.encryptor().finalize()
return iv + enc
def aes_decrypt (key: bytes , ciphertext: bytes ) -> str :
"""前 16 字节为 IV,后面为密文;解密后去掉 PKCS7 padding。"""
iv, enc = ciphertext[:16 ], ciphertext[16 :]
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
dec = cipher.decryptor().update(enc) + cipher.decryptor().finalize()
unpadder = padding.PKCS7(128 ).unpadder()
return (unpadder.update(dec) + unpadder.finalize()).decode()
key = os.urandom(32 )
ct = aes_encrypt(key, "hello api" )
print ("解密结果:" , aes_decrypt(key, ct))
private_key = rsa.generate_private_key(
public_exponent=65537 ,
key_size=2048 ,
backend=default_backend(),
)
public_key = private_key.public_key()
def rsa_encrypt (pub_key, data: bytes ) -> bytes :
"""用对方公钥加密,仅对方私钥可解密;数据不宜过长,适合加密 AES 的 key。"""
return pub_key.encrypt(
data, rsa_padding.OAEP(rsa_padding.MGF1(hashes.SHA256()), hashes.SHA256(), None )
)
六、小结与选型建议
按场景选方式 场景 建议方式 内部/简单对接 API Key 或简单签名 开放 API、防篡改 签名(HMAC)或 AK/SK 需加密传输 在鉴权之上加 AES/RSA 或混合加密 无状态、多服务 JWT 第三方授权、开放平台 OAuth 2.0
按架构/部署形态选型(Web 前后端、车机端云、云对云、A2A) 架构场景 说明 常用鉴权与传输方式 注意点 Web 前后端 浏览器/SPA/小程序 ↔ 后端服务 JWT、Session + Cookie、OAuth 2.0 授权码 Token 存放与刷新、CORS、HTTPS;避免敏感密钥暴露在前端 车机端云 车机/T-Box/IVI ↔ 车云平台 设备证书 + 签名、AK/SK、或厂商自定义签名协议 弱网与断网续传、设备身份绑定、OTA 与密钥轮换 云对云 API 某云/自建服务 ↔ 另一云或第三方 API AK/SK、OAuth 2.0 客户端凭证、mTLS、API Key 服务账号与权限最小化、审计与调用限流、密钥轮换与保管 A2A(应用对应用) 服务 ↔ 服务、API ↔ API,无用户参与 同云对云:AK/SK、Client Credentials、API Key、签名 机器身份、调用链与审计、idempotency 与重试策略
选型时可以先看「按场景」或「按架构」表,再回到前文第三节(签名)、第四节(凭证)、第五节(加解密)对号入座;需要高并发、异步框架里调接口时,可优先用 httpx 的异步写法。
七、参考资料 相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online