Node.js中调用Sequelize模型的generateToken方法提示不是函数如何解决
问题根因
- Sequelize的模型方法分为类静态方法和实例方法:你当前直接把
generateToken挂载到模型类上,属于类静态方法,只能通过db.users.generateToken()调用,无法通过findOne返回的单条用户实例调用 - 额外隐藏问题:模型内未导入
jsonwebtoken依赖、generateToken没有返回生成的token、模型catch块中response为未定义变量、登录接口重复导入模型属于多余操作
修复步骤
1. 修改users模型代码
将方法挂载到模型原型上,成为所有用户实例可调用的公共方法,补全依赖导入和返回逻辑:
const jwt = require('jsonwebtoken') // 新增导入JWT依赖 module.exports = (sequelize, Sequelize) => { // 将变量名从Tutorial改为User更语义化,不改也不影响运行 const User = sequelize.define("users", { age: { type: Sequelize.INTEGER }, name: { type: Sequelize.STRING }, email: { type: Sequelize.STRING }, password: { type: Sequelize.STRING } }); // 挂载到原型上,成为实例方法,所有查询返回的用户实例都可以调用 User.prototype.generateToken = async function () { try { // this指向当前调用方法的用户实例,可以直接获取用户字段 const token = jwt.sign({ _id: this.id }, "ThisIsTaskApp") console.log(token) return token // 新增返回生成的token } catch (error) { console.log('生成token出错' + error) throw error // 错误抛到接口层处理 } } return User; };
2. 修改登录接口代码
删除冗余导入,修正异步调用逻辑,补全token返回逻辑:
const jwt = require('jsonwebtoken') const userModel = db.users; // 重命名避免和后续查询出的user变量重名覆盖 // 删掉多余的模型导入代码:const generateToken = require('./models/users') app.post('/login', async (req, res) => { try { const email = req.body.email; const password = req.body.password; // 统一用await写法避免嵌套回调 const user = await userModel.findOne({ where: { email: email, password: password } }) if (user === null) { return res.status(404).json({ message: 'Auth Failed' }) } // 异步方法需要加await等待返回结果 const token = await user.generateToken() // 将token和用户信息一起返回 res.status(200).json({ user: user, token: token }) } catch (error) { console.log(error) return res.status(400).json({ 'status': 400 }) } })
注意事项
- 生产环境不要明文存储密码,建议使用bcrypt等工具加密后存储
- JWT签名密钥不要硬编码在代码中,建议放到环境变量中读取
- 可以给JWT添加过期时间,避免token长期有效带来的安全风险
内容的提问来源于stack exchange,提问作者AskAnyWay
相关产品推荐
相关产品推荐

