Node.js+Angular中Passport JWT返回Unauthorized问题求助
问题背景
在Node.js(Sequelize+MySQL)和Angular项目中使用Passport JWT做身份验证,请求始终返回unauthorized错误,已尝试Stack Overflow方案但无效。相关代码如下:
Passport JWT配置代码
require('dotenv').config() const user = require('../models/user'); const SECRET = process.env.REFRESH_TOKEN_SECRET; const { Strategy, ExtractJwt } = require('passport-jwt'); const options = { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: SECRET } module.exports = (passport) => { passport.use(new Strategy(options, async (payload, done) => { await user.findByPk(payload.userId).then(user => { if (user) { return done(null, user); } return done(null, false); }).catch(error => { return done(null, error); }); })); }
项目初始化配置(app.js)
app.use(passport.initialize()); require("./middleware/passport")(passport);
身份验证中间件(auth.js)
exports.userAuth = passport.authenticate("jwt", { session: false });
路由使用示例
router.get( '/categories', userAuth, checkRole(['admin', 'superadmin']), categoryController.getAllCategories );
Angular拦截器代码
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // add authorization header with jwt token if available let currentUser = this.authenticationService.currentUserValue; if (currentUser && currentUser.token) { request = request.clone({ setHeaders: { Authorization: `Bearer ${currentUser.token}` } }); } return next.handle(request); }
可能的问题及排查步骤
1. JWT密钥不匹配
- 检查生成JWT时使用的密钥和Passport配置中
SECRET是否一致:当前代码用的是REFRESH_TOKEN_SECRET,确认生成访问令牌时是否用了同一个密钥。很多项目会区分访问令牌密钥和刷新令牌密钥,如果签令牌和验令牌用的密钥不一致,必然验证失败。 - 直接打印
process.env.REFRESH_TOKEN_SECRET,确认环境变量是否正确加载,有没有拼写错误(比如大小写、下划线)。
2. JWT Payload中的userId字段不匹配
- 生成JWT时,确认存入的用户ID字段是
userId还是其他(比如id)。如果生成时用的是payload: { id: user.id },但Passport里用payload.userId查询,自然找不到用户,返回false导致未授权。 - 在Passport的验证回调里加日志,打印
payload内容,确认userId是否存在且正确:passport.use(new Strategy(options, async (payload, done) => { console.log('JWT Payload:', payload); // 新增日志 await user.findByPk(payload.userId).then(user => { // ...原有代码 }); }));
3. Sequelize查询用户时的问题
- 确认
user.findByPk(payload.userId)确实能查到用户:可以单独写个测试脚本,用已知存在的用户ID调用这个方法,看是否返回用户实例。 - 注意Sequelize的
findByPk默认会过滤软删除(带deletedAt字段)的用户,确认目标用户没有被软删除。 - 回调里的错误处理逻辑有误:
catch(error)里返回done(null, error),Passport会把错误对象当成用户返回,应该改成done(error, false),或者直接抛出错误。
4. 请求头中的Token格式问题
- 检查Angular拦截器生成的
Authorization头格式是否正确:必须是Bearer+空格+令牌,不能有多余空格或拼写错误(比如bearer小写)。 - 在后端加日志,打印
req.headers.authorization,确认Token是否正确传递到后端:app.use((req, res, next) => { console.log('Authorization Header:', req.headers.authorization); next(); }); - 确认后端CORS配置允许携带自定义头,避免请求头被拦截。
5. Token已过期或无效
- 生成JWT时确认设置了合理的过期时间(比如
expiresIn: '1h'),如果Token过期,Passport会直接返回未授权。 - 解析前端发送的Token,确认签名是否有效、过期时间是否正常、Payload内容是否正确。
6. Passport初始化顺序问题
- 确认
app.use(passport.initialize())是在路由之前配置的,且require("./middleware/passport")(passport)正确执行了策略注册。如果路由先于Passport初始化,策略未注册会导致验证失败。
内容的提问来源于stack exchange,提问作者Prasad Gavande
相关产品推荐
相关产品推荐

