FastAPI+SQLAlchemy实现JWT校验时payload['sub']查询用户返回None问题
代码问题汇总
核心问题(导致get_user_by_id返回None的直接原因)
- 注册逻辑重复创建用户,生成token的用户未入库:
你在create_user接口中先手动实例化了一个User对象,用这个临时对象的id生成激活token、设置confirmation字段,但最后调用users.register_user(form_data)时,该方法内部又重新实例化了一个全新的User对象存入数据库,你之前设置过confirmation的临时用户根本没有入库,所以verify接口通过token里的sub(也就是临时用户的id)查库肯定返回None。
正确的做法是不要在接口层重复实例化User,所有数据库操作都放到数据访问层的方法里,register_user方法要接收生成好的confirmation值,入库后返回正确的用户对象。
其他严重问题
- 参数类型不匹配导致查询失效:
User表的id字段是UUID(as_uuid=True)类型,你调用get_user_by_id时传入的是字符串类型的payload['sub'],部分异步SQLAlchemy驱动不会自动把字符串转成UUID对象,需要手动转:from uuid import UUID user = await users.get_user_by_id(id=UUID(payload['sub'])) - jti校验逻辑完全错误:
你写的await users.get_confirmation_uuid(str(User.confirmation)) != payload['jti']存在两个错误:User.confirmation是模型类的属性,直接转str拿到的是SQL表达式字符串,不是当前查询到的用户的confirmation值get_confirmation_uuid返回的是SQLAlchemy查询结果对象,不是字符串,和payload['jti']对比永远不成立
正确的做法是直接用已经查到的user对象对比,且get_confirmation_uuid方法完全多余,可以直接删除:
if not user or str(user.confirmation) != payload['jti']: raise invalid_token_error - 用户激活修改未持久化:
verify接口中你修改了user.confirmation = None和user.is_active = True之后,既没有把修改add到session,也没有commit/flush,修改不会同步到数据库。而且你最后调用register_user(user)是完全错误的,这个方法是用来新建用户的,会重复创建数据。
正确的做法是在Users类里新增一个更新用户的方法,或者直接在verify逻辑里提交修改:self.db_session.add(user) await self.db_session.commit() await self.db_session.refresh(user) - 密码存储逻辑错误:
你在create_user接口中已经用Auth.get_password_hash(form_data.password)计算了密码哈希,但是register_user方法里直接把user.password(明文密码)赋值给了hashed_password字段,导致存的是明文密码,完全不符合安全要求。 - token过期异常捕获错误:
你在verify接口中捕获的是jwt.JWSError,但JWT过期抛出的是jwt.ExpiredSignatureError,会导致过期token不会返回正确的“Token已过期”提示,而是走500错误。
内容的提问来源于stack exchange,提问作者dougj
相关产品推荐
相关产品推荐

