使用Passport.js时报错req.isAuthenticated is not a function如何解决?
问题原因
- 中间件挂载实例错误,未生效
你在路由文件内部新建了独立的app实例,将session、passport相关的中间件全部挂载到了这个内部的app上,但你最终导出的是router,项目入口文件引入该路由时,使用的是入口的app实例,这个实例从未加载过passport相关中间件,因此req对象上不会被挂载isAuthenticated方法。 passport-config.js存在多处语法/逻辑错误- LocalStrategy的验证函数参数错误:你写的
authenticateUser只接收了done参数,函数内部直接使用的req未被传入,无法获取请求参数 serializeUser和deserializeUser的参数错误,且访问了不存在的变量:两个方法的第一个参数分别是用户对象、用户id,你都未声明,同时代码中引用的userFound是authenticateUser内部的局部变量,外部无法访问,会直接报错
- LocalStrategy的验证函数参数错误:你写的
修复方案
1. 调整项目结构,修正中间件挂载逻辑
把路由文件里的app实例创建、中间件挂载逻辑全部删除,移到项目入口文件(比如app.js/index.js)中,入口文件参考结构:
const express = require('express') const passport = require('passport') const flash = require('express-flash') const session = require('express-session') const methodOverride = require('method-override') const userRouter = require('./routes/users.route') // 引入你的路由文件 const initializePassport = require('./passport-config') initializePassport(passport) const app = express() // 挂载全局中间件,顺序不能乱 app.use(express.json()) // 解析json格式请求体 app.use(express.urlencoded({ extended: false })) // 解析表单格式请求体 app.use(flash()) app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false })) app.use(passport.initialize()) app.use(passport.session()) app.use(methodOverride('_method')) // 挂载路由 app.use(userRouter) app.listen(3000, () => console.log('服务启动成功'))
路由文件中仅保留路由定义、校验中间件定义即可。
2. 修正passport-config.js代码
const User = require('./models/user.model') const LocalStrategy = require('passport-local').Strategy const bcrypt = require('bcrypt') function initializePassport(passport) { // 开启passReqToCallback才能在验证函数中拿到req对象 passport.use(new LocalStrategy( { usernameField: 'email', passReqToCallback: true }, async (req, email, password, done) => { try { /* 校验对应邮箱的用户是否存在 */ const userFound = await User.findOne({email: email}) if (!userFound) return done(null, false, {message: 'Cannot find user with that email'}) /* 校验密码是否正确 */ const checkPassword = await bcrypt.compare(password, userFound.password) if (checkPassword) { return done(null, userFound) } else { return done(null, false, {message: 'Incorrect password'}) } } catch (err) { return done(err) } })) // 修正序列化参数 passport.serializeUser((user, done) => { done(null, user.id) }) // 修正反序列化逻辑,根据存储的id查询用户 passport.deserializeUser(async (id, done) => { const user = await User.findById(id) done(null, user) }) } module.exports = initializePassport
额外优化建议
- 注册接口的
user.save()是异步方法,建议加上await,避免逻辑时序问题 - 新版Passport中
req.logOut()是异步方法,需要传入回调函数处理异常,参考写法:
router.delete('/logout', (req, res, next) => { req.logOut((err) => { if (err) return next(err) res.redirect('/login') }) })
内容的提问来源于stack exchange,提问作者German Cocca
相关产品推荐
相关产品推荐

