You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flask中用JWT-extended生成含AccessToken的API响应HMAC校验和

嘿,这个需求很靠谱——把access_token纳入HMAC计算确实能大幅提升消息完整性校验的安全性,毕竟只有持有合法token的客户端和服务端能参与这个校验逻辑。下面给你一步步拆解实现方案:

实现步骤

1. 准备安全的HMAC密钥

首先得准备一个强HMAC密钥,绝对不要硬编码到代码里,建议通过环境变量注入(比如用os.getenv读取)。密钥要足够长且随机,比如32位以上的随机字符串。

2. 获取当前请求的原始access_token

因为@jwt_required已经完成了token的合法性校验,我们可以直接从请求头中提取原始的token字符串(注意不要用解码后的payload,我们需要的是客户端发送的原始token):

from flask import request

auth_header = request.headers.get('Authorization')
# 理论上@jwt_required已经拦截了非法请求,这里的判断是兜底
if not auth_header or not auth_header.startswith('Bearer '):
    return {"error": "Invalid authorization header"}, 401
access_token = auth_header.split(' ')[1]

3. 构建待签名的标准化数据

为了保证客户端和服务端生成的哈希完全一致,必须固定JSON序列化的规则:

  • 先准备基础返回数据(不要包含checksum)
  • 把access_token加入到待签名的数据集里
  • 按键名排序序列化,去掉多余空格

示例代码:

import json
from datetime import datetime

# 基础返回数据,用UTC时间避免时区差异
response_data = {
    "message": "important-info",
    "ts": datetime.utcnow().isoformat()
}

# 构建待签名数据(包含access_token)
data_to_sign = response_data.copy()
data_to_sign['access_token'] = access_token

# 标准化序列化:按键排序、无多余空格
serialized_data = json.dumps(data_to_sign, sort_keys=True, separators=(',', ':'))

4. 生成HMAC校验和

用Python内置的hmac模块生成SHA256哈希(也可以根据需求换成SHA512等更强的算法):

import hmac
import hashlib
import os

# 从环境变量读取密钥,兜底判断防止漏配置
hmac_secret = os.getenv("HMAC_SECRET_KEY")
if not hmac_secret:
    raise ValueError("HMAC_SECRET_KEY environment variable is not set!")

# 生成HMAC哈希
checksum = hmac.new(
    hmac_secret.encode('utf-8'),
    serialized_data.encode('utf-8'),
    hashlib.sha256
).hexdigest()

5. 整合校验和并返回

最后把生成的checksum加入到基础返回数据中,返回给客户端:

response_data['checksum'] = checksum
return response_data, 200
完整代码示例

把所有逻辑整合到你的Data类里:

from flask_jwt_extended import jwt_required
from flask_restful import Resource
from flask import request
import json
import hmac
import hashlib
import os
from datetime import datetime

class Data(Resource):
    @jwt_required()
    def get(self):
        """ GET Response message with HMAC integrity checksum. """
        # 提取原始access_token
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            return {"error": "Invalid authorization header"}, 401
        access_token = auth_header.split(' ')[1]

        # 准备基础返回数据
        response_data = {
            "message": "important-info",
            "ts": datetime.utcnow().isoformat()
        }

        # 构建待签名数据集
        data_to_sign = response_data.copy()
        data_to_sign['access_token'] = access_token

        # 标准化序列化
        serialized_data = json.dumps(data_to_sign, sort_keys=True, separators=(',', ':'))

        # 生成HMAC校验和
        hmac_secret = os.getenv("HMAC_SECRET_KEY")
        if not hmac_secret:
            raise ValueError("HMAC_SECRET_KEY environment variable not configured")
        
        checksum = hmac.new(
            hmac_secret.encode('utf-8'),
            serialized_data.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()

        # 加入校验和并返回
        response_data['checksum'] = checksum
        return response_data, 200
客户端验证逻辑

客户端拿到返回结果后,需要执行和服务端完全一致的逻辑来校验:

  • 从返回结果中取出message、ts,加上自己持有的access_token,构建相同的data_to_sign字典
  • 用相同的JSON序列化规则(按键排序、无多余空格)生成序列化字符串
  • 用共享的HMAC密钥和相同算法生成哈希
  • 对比生成的哈希和返回的checksum,一致则说明消息完整且未被篡改
关键注意事项
  • 密钥安全:HMAC密钥必须在服务端和客户端之间安全共享,绝对不能泄露给第三方。建议用密钥管理工具(比如AWS Secrets Manager、HashiCorp Vault)存储,而不是环境变量(如果是生产环境)。
  • 防止重放攻击:建议在客户端同时校验ts的时效性,比如拒绝超过5分钟的返回结果,避免攻击者重复发送已截获的合法响应。
  • 序列化一致性:客户端和服务端的JSON序列化规则必须完全一致(包括键排序、分隔符、日期格式),哪怕是一个空格的差异都会导致哈希不匹配。
  • token有效性:客户端在验证checksum前,要确保自己的access_token未过期且合法,避免用过期token生成的哈希和服务端不一致。

内容的提问来源于stack exchange,提问作者Daedalus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:17:49