使用flask-jwt时遇到ObjectId类型对象无法JSON序列化的TypeError如何解决
问题原因
这个报错的核心是Python标准json库无法序列化MongoDB的ObjectId类型,Flask-JWT生成token时会默认序列化用户标识字段,你当前代码中用户主键是ObjectId类型,没有做序列化转换就直接参与json编码就会触发该错误。
解决方案
按以下步骤修改代码即可:
- 修正Customer类的to_json方法,将ObjectId转为字符串
# customer.py 中修改to_json方法 def to_json(self): return { "_id": str(self._id), "tel": self.tel, "password": self.password, }
- 为Flask应用配置自定义JSON编码器,全局支持ObjectId序列化
在你的Flask应用初始化文件中添加如下代码:
import json from bson import ObjectId class CustomJSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, ObjectId): return str(obj) return super().default(obj) # 替换你的app实例的json编码器 app.json_encoder = CustomJSONEncoder
- 调整JWT身份处理逻辑,兼容字符串格式的ObjectId查询
首先自定义JWT身份提取回调,确保写入payload的用户ID是字符串类型:
# 放在JWT初始化后的位置 @jwt.jwt_identity_handler def jwt_identity(user): return str(user._id)
然后修改service.py中的identity函数,将payload中读取的字符串ID转回ObjectId再查询:
# 先导入bson,修改identity方法 import bson def identity(payload): _id = bson.ObjectId(payload['identity']) return find_by_id.get(_id)
- 可选优化(强烈建议修改)
你当前代码中find_by_username和find_by_id是模块加载时一次性生成的全局字典,后续新增的用户无法被检索到,建议改为实时查询数据库:
# service.py 调整为动态查询 def auth(username, password): user = Customer.objects(tel=username).first() if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')): return user def identity(payload): _id = bson.ObjectId(payload['identity']) return Customer.objects(_id=_id).first()
这样就不需要预加载所有用户数据,也避免了新用户无法登录的问题。
内容的提问来源于stack exchange,提问作者Amoungui Serge
相关产品推荐
相关产品推荐

