MERN项目中passport-jwt授权失败问题求助
MERN项目中passport-jwt授权失败排查
问题概述
在MERN项目中使用passport-jwt实现身份验证时,向/profile路由发送包含Bearer <generated-token>授权头的GET请求,始终返回"unauthorized"响应。尝试过ExtractJwt.fromAuthHeaderWithScheme('jwt')等多种token提取方式,问题仍未解决。
依赖版本
"cors": "2.8.5", "dotenv": "16.0.3", "express": "4.18.2", "jsonwebtoken": "9.0.0", "mongoose": "7.0.4", "nodemon": "2.0.22", "passport": "0.6.0", "passport-jwt": "4.0.1"
相关代码
server/config/passport.js
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); opts.secretOrKey = process.env.SECRET_KEY; passport.use(new JwtStrategy(opts, function(jwt_payload, done) { User.findOne({ _id: jwt_payload.sub }) .then(user => { if (user) { return done(null, user); } else { return done(null, false); } }) .catch(err => { return done(err, false); }); }));
server/app.js路由代码
//login route app.post("/login", async (req,res) =>{ const user = await User.findOne({phone : req.body.phone}); if(!user){ res.status(400).send("User not found!"); } if(!bcrypt.compareSync(req.body.password, user.password)){ res.status(400).send("Incorrect password!"); } const payload = { id: user._id, phone: user.phone } const token = jwt.sign(payload, process.env.SECRET_KEY, {expiresIn: "2d"}); return res.status(200).send({ success : true, message : "Log in successful", token : "Bearer "+token}); }) //profile route app.get('/profile', passport.authenticate('jwt', { session: false }), function(req, res) { res.status(200).send({ message: "Tomar account", token: "Bearer "+token, user: { id: req.user._id, phone: req.user.phone } }); } );
排查与解决方向
1. JWT Payload字段不匹配(核心问题)
生成JWT时,payload里定义的是id: user._id,但在passport的JwtStrategy中,查询条件用的是jwt_payload.sub——默认情况下jsonwebtoken不会自动将id映射为sub字段,导致查询不到用户,直接返回未授权。
解决方法二选一:
- 修改login路由的payload,将用户ID存入
sub字段:const payload = { sub: user._id, // 替换原来的id phone: user.phone } - 或者修改passport配置中的查询条件,使用payload里的
id字段:User.findOne({ _id: jwt_payload.id })
2. 环境变量加载顺序问题
确保dotenv在passport配置文件加载前完成初始化。如果server/config/passport.js先于dotenv.config()加载,会导致process.env.SECRET_KEY为空,JWT验证失败。
修正方式:在app.js最顶部先加载dotenv:
require('dotenv').config(); // 再引入passport配置 require('./config/passport');
3. Login路由错误处理漏洞
当前login路由中,当用户不存在或密码错误时,只发送响应但未终止后续代码执行,可能导致逻辑混乱(比如后续仍会生成token)。需要在错误响应后添加return:
if(!user){ return res.status(400).send("User not found!"); } if(!bcrypt.compareSync(req.body.password, user.password)){ return res.status(400).send("Incorrect password!"); }
4. Profile路由变量未定义问题
Profile路由中尝试返回token变量,但该变量仅在login路由中定义,会导致服务器500错误。需要移除该字段,或者从请求头中获取并返回:
res.status(200).send({ message: "Tomar account", user: { id: req.user._id, phone: req.user.phone } });
内容的提问来源于stack exchange,提问作者SharifMAbdullah
相关产品推荐
相关产品推荐

