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

使用Flask_JWT与Mongoengine时遇'dict' object has no attribute 'id'错误求助

解决Flask_JWT + Mongoengine 报错:'dict' object has no attribute 'id'

这个错误我之前也踩过坑,核心原因其实很直白:Flask-JWT的authenticate方法要求返回用户模型的实例,而不是字典。

看你的代码,大概率是在authenticate方法里查询到用户后,返回了user.to_json()的结果(毕竟你写了这个序列化方法),但这个方法返回的是一个字典对象。当Flask-JWT尝试访问user.id来生成token时,字典自然没有id属性,直接就抛出这个错误了。

具体修复步骤:

1. 修正authenticate方法,返回UserModel实例

把返回字典的逻辑删掉,直接返回查询到的用户对象:

def authenticate(username, password):
    # 根据用户名查询用户
    user = UserModel.objects(username=username).first()
    # 验证密码(这里必须提一句:实际生产环境绝对不能明文存密码!一定要用bcrypt/pbkdf2等哈希算法加密后再存储)
    if user and user.password == password:
        return user  # 返回UserModel实例,不是to_json()生成的字典

2. 让Flask-JWT能正确识别用户ID

Mongoengine默认用pk作为主键(类型是ObjectId),而Flask-JWT默认会尝试读取user.id来生成token。这里有两种简单的解决方式:

方式一:给UserModel添加id属性的@property

在你的UserModel里加一个属性方法,把pk转成字符串返回,适配Flask-JWT的默认逻辑:

class UserModel(Document):
    first_name = StringField(required=True, max_length=50)
    last_name = StringField(required=True, max_length=50)
    username = StringField(required=True)
    password = StringField(required=True, min_length=6)
    
    @property
    def id(self):
        return str(self.pk)  # 把ObjectId转成字符串,方便JWT使用
    
    def to_json(self):
        return {
            "id": str(self.pk),
            "first_name": self.first_name,
            "last_name": self.last_name,
            "username": self.username,
            # 这里强烈建议删掉密码字段!敏感信息绝对不能对外暴露
            # "password": self.password
        }
方式二:自定义Flask-JWT的identity处理函数

如果不想修改模型,可以在初始化JWT的时候,指定identity函数让它用pk来查询用户:

from flask import Flask
from flask_jwt import JWT
from your_module import UserModel

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secure-secret-key'  # 务必设置安全的密钥

def authenticate(username, password):
    user = UserModel.objects(username=username).first()
    if user and user.password == password:
        return user

def identity(payload):
    # payload里的identity就是用户ID,这里用pk查询用户
    user_id = payload['identity']
    return UserModel.objects(pk=user_id).first()

jwt = JWT(app, authenticate, identity)

额外的安全提醒

最后必须强调:明文存储密码是严重的安全漏洞!推荐用bcrypt来处理密码:

# 先安装依赖:pip install bcrypt
import bcrypt

class UserModel(Document):
    # ...你的字段定义
    
    def set_password(self, password):
        # 生成盐并哈希密码
        self.password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
    
    def check_password(self, password):
        # 验证密码是否匹配
        return bcrypt.checkpw(password.encode('utf-8'), self.password.encode('utf-8'))

# 注册用户时调用set_password加密
user = UserModel(first_name="John", last_name="Doe", username="johndoe")
user.set_password("your-secure-password")
user.save()

# 认证时用check_password验证
def authenticate(username, password):
    user = UserModel.objects(username=username).first()
    if user and user.check_password(password):
        return user

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:46:33