签发JWT时遇「Expected 'payload' to be a plain object」错误求助
解决JWT生成错误:「Expected 'payload' to be a plain object」
问题场景
在Node.js+TypeScript+Hapi.js+Docker环境下,生成JWT用于访问其他路由时触发错误:Expected "payload" to be a plain object。
错误栈信息
apis_1 | Error: Expected "payload" to be a plain object. apis_1 | at validate (/lens-apis/node_modules/jsonwebtoken/sign.js:40:11) apis_1 | at validatePayload (/lens-apis/node_modules/jsonwebtoken/sign.js:62:10) apis_1 | at Object.module.exports [as sign] (/lens-apis/node_modules/jsonwebtoken/sign.js:114:7) apis_1 | at /lens-apis/dist/org/signup/signup.route.js:115:37 apis_1 | at Generator.next (<anonymous>) apis_1 | at fulfilled (/lens-apis/dist/org/signup/signup.route.js:5:58) apis_1 | at processTicksAndRejections (internal/process/task_queues.js:95:5)
相关代码
JWT生成逻辑
if (!user) { return h.response({ message: "User does not exist", }); } else if (!upassword) { return h.response({ message: "Your Password is incorrect", }); } else { let token = jwt.sign(user, process.env.JWT_SECRET, { expiresIn: "1h", }); if (!token) { console.log("token not found"); } return h.response({ message: "you have successfully logged in", token: `${token}`, }); }
导入代码
import { ServerRoute } from "@hapi/hapi"; import Joi, { options } from "joi"; import { ISignup, IsLogin } from "./signup.types"; import firebase from "firebase-admin"; import { User } from "../../user/user.model"; import { Org } from "../org.model";
解决方案
错误原因是user是SQL ORM的模型实例(而非纯JavaScript对象),jsonwebtoken的sign方法要求payload必须是无额外原型方法/元数据的普通键值对对象。以下是几种可行的解决方式:
1. 手动提取必要字段构建纯对象(推荐)
只将JWT需要的核心字段(如用户ID、邮箱)作为payload,既符合要求又减少token体积、提升安全性:
// 提取需要的字段 const tokenPayload = { userId: user.id, email: user.email, // 按需添加其他必要字段,避免传入整个模型实例 }; let token = jwt.sign(tokenPayload, process.env.JWT_SECRET, { expiresIn: "1h", });
2. 使用ORM内置方法转换为纯对象
如果使用Sequelize等常见SQL ORM,可调用实例的内置方法转换:
// Sequelize 可用 toJSON() let token = jwt.sign(user.toJSON(), process.env.JWT_SECRET, { expiresIn: "1h" }); // 或者 get({ plain: true }) let token = jwt.sign(user.get({ plain: true }), process.env.JWT_SECRET, { expiresIn: "1h" });
3. 通用序列化转换(兜底方案)
通过JSON序列化再反序列化,强制将实例转为纯对象(注意:可能丢失不可序列化的属性):
const plainUser = JSON.parse(JSON.stringify(user)); let token = jwt.sign(plainUser, process.env.JWT_SECRET, { expiresIn: "1h" });
内容的提问来源于stack exchange,提问作者mzee
相关产品推荐
相关产品推荐

