基于Node.js+Express+JWT+Sequelize的认证服务获取用户失败问题
问题:JWT认证后获取当前用户接口返回“User not found”
使用Node.js、Express.js、JWT和Sequelize开发API认证服务,登录接口可成功返回token,但携带token请求/api/auth/me接口时,收到“User not found”错误。
相关代码
路由文件 routes/api/auth.js
const express = require('express'); const router = express.Router(); const { protect } = require('../../middleware/auth'); const { register, login, getMe, } = require('../../controllers/auth'); router.post('/register', register); router.post('/', login); router.get('/me', protect, getMe); module.exports = router;
控制器方法
//@route POST api/auth //@desc Authenticate user & get token //@access public exports.login = asyncHandler(async (req, res, next) => { const { email, password } = req.body; //Validate email and password if(!email || !password){ return res.status(400).json({ errors: [{ msg: 'Please provide an email and password'}]}); } //See if user exists let user = await User.findOne({ where: { email: email }, attributes: ['email', 'password'] }); if(!user){ return res.status(400).json({ errors: [{ msg:'Invalid credentials' }] }); } //Compare the input password, plane text, to the encrypted password. const isMatch = await user.matchPassword(password); if(!isMatch){ return res.status(401).json({ errors: [{ msg:'Invalid credentials' }] }); } //Return jsonwebtoken -> this for users to be logged in right after registration sendTokenResponse(user, 200, res); }); //@desc Get current logged in user //@route GET api/auth/me //@access Private exports.getMe = asyncHandler(async (req, res, next) => { const user = await User.findByPk(req.user.id); res.status(200).json({ success: true, data: user }); }) //Get Token from model, create a cookie and send response const sendTokenResponse = (user, statusCode, res) => { // Create token const token = user.getSignedJwtToken(); const options = { expires: new Date( Date.now() + process.env.JWT_COOKIE_EXPIRE * 24 * 60 * 60 * 1000 ), httpOnly: true }; if (process.env.NODE_ENV === 'production') { options.secure = true; } res .status(statusCode) .cookie('token', token, options) .json({ success: true, token }); };
路由保护中间件
const jwt = require('jsonwebtoken'); const asyncHandler = require('./async'); const ErrorResponse = require('../utils/errorResponse'); const User = require('../models/User.model'); //Protect Routes exports.protect = asyncHandler(async (req, res, next) => { let token; if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) { token = req.headers.authorization.split(' ')[1]; } else if (req.cookies.token) { token = req.cookies.token; } //Make sure token exists if(!token){ return next(new ErrorResponse('Not authorized to access this route', 401)); } try { const decoded = jwt.verify(token, process.env.JWT_SECRET); const user = await User.findByPk(decoded.id); if (!user) { return next(new ErrorResponse('User not found', 404)); } req.user = user; next(); } catch (error) { return next(new ErrorResponse('Not authorized to access this route', 401)); } });
User模型的签名方法
User.prototype.getSignedJwtToken = function() { return jwt.sign({ id: this.id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRE }); };
问题原因与修复方案
核心问题
在login方法查询用户时,指定了attributes: ['email', 'password'],导致返回的user对象缺失id字段。而生成JWT的getSignedJwtToken方法依赖this.id,此时this.id为undefined,最终JWT中存储的id是undefined。后续protect中间件用decoded.id查询用户时自然找不到,返回“User not found”。
修复步骤
- 修改登录接口的用户查询逻辑:移除
attributes限制,或者明确包含id字段:
// 方案1:获取用户所有字段 let user = await User.findOne({ where: { email: email } }); // 方案2:仅获取需要的字段(包含id) let user = await User.findOne({ where: { email: email }, attributes: ['id', 'email', 'password'] });
- 可选优化:减少重复数据库查询:
protect中间件已经查询到用户并挂载到req.user,getMe方法可直接返回该对象,无需再次查询:
exports.getMe = asyncHandler(async (req, res, next) => { res.status(200).json({ success: true, data: req.user }); })
内容的提问来源于stack exchange,提问作者tukitooo1998
相关产品推荐
相关产品推荐

