在我的一个路由中,护照JWT req.user未定义

3
我正在尝试在我的Express应用程序中设置JWT,但遇到了一些问题!我认为现在大部分都已经解决了,我有一个正确工作并生成有效令牌的注册路由和登录路由,我还有一个在“/users”路由中测试身份验证的路由,这一切都很好。但是我有另一个文件包含“/api”路由,这是身份验证实际上很重要的地方,我有一个类似的测试路由尝试访问req.user(就像我在另一个路由中所做的一样),但似乎req.user未定义。通过一些调试,看起来用户在req.account中,这非常奇怪,我不明白为什么它不在req.user中。
我在/config/passport.js中定义我的jwt策略。
'use strict';
const User = require('../models/user'),
      config = require('./main'),
      JwtStrategy = require('passport-jwt').Strategy,
      ExtractJwt = require('passport-jwt').ExtractJwt;

//exported to be used by passport in server set up
module.exports = function (passport) {
  const jwtOptions = {  
    // Telling Passport to check authorization headers for JWT
    jwtFromRequest: ExtractJwt.fromAuthHeader(),
    // Telling Passport where to find the secret
    secretOrKey: config.secret
  };

  const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) {
    User.findById(payload._id, function(err, user) {
      if (err) { return done(err, false); }

      if (user) {
        done(null, user);
      } else {
        done(null, false);
      }
    });
  });

  passport.use(jwtLogin);

}

护照作为参数传递给此函数,并在主Express文件中初始化。

以下是/users路由文件,它可以正常工作。通过Authorization头和'JWT '向/users/isAuth发送GET请求可以正常工作,并且我会收到发送回来的用户名。

"use strict";
const   express = require('express'),
        router = express.Router(),
        jwt = require('jsonwebtoken'),
        User = require('../models/user'),
        config = require('../config/main'),
        passport = require ('passport');

function generateToken(user) {
    return jwt.sign({_id: user._id}, config.secret, {
        expiresIn: 10080
    });
}
.
. Here are routes for login and register they perform as expected
. and work fine
.
/*  ==================================
       Test Authentication Route
    ================================== */
router.get('/isAuth', passport.authenticate('jwt', { session: false }), function(req, res) {
    console.log(req.user);
    res.json({username: req.user.username});
});



module.exports = router;

在这个文件中,对于发送请求到GET /api/testAuth的api路由,使用相同的令牌和相同的头信息,我得不到req.user,并且在控制台上看到req.user为undefined。但是在控制台中似乎有用户对象,就像req.account一样?我不明白这里发生了什么,希望有人能帮助!
"use strict";
const   express = require('express'),
        router = express.Router(),
        jwt = require('jsonwebtoken'),
        Server = require('../models/server'),
        passport = require('passport');

// Test route to see if logged in user is matt
router.get('/testAuth', passport.authorize('jwt', { session: false }), function(req, res) {
    console.log(req.user);
    if (req.user) {
        if(req.user.username == "matt") {
        res.send("You are matt!");
        } else {
        res.send("You are not matt!");
        }
    } else {
        res.send("no req.user");
    }

})

module.exports = router;

1
Samson Maosa的回答解决了我的问题。 - Jeex Box
2个回答

17

req.user对象仅在您使用需要会话的passport身份验证策略时设置。在这种情况下,认证是无状态的,因为您已经指定了{session: false},这对于API来说是正确的方法。因此,会话中没有用户对象。以下是我如何在passport.authenticate中间件中设置req.user对象:

  1. 修改您的jwtOptions以启用将req对象传递给JwtStrategy函数:

  2. const jwtOptions = {  
        // Telling Passport to check authorization headers for JWT
        jwtFromRequest: ExtractJwt.fromAuthHeader(),
        // Telling Passport where to find the secret
        secretOrKey: config.secret,
        passReqToCallback: true, //<= Important, so that the verify function can accept the req param ie verify(req,payload,done)
      };
    
  3. 修改您的JwtStrategy参数,将请求对象作为第一个参数包含在内;然后在if (user)块中,只需将返回的用户对象分配给req.user

  4. const jwtLogin = new JwtStrategy(jwtOptions, function(req, payload, done) {
        User.findById(payload._id, function(err, user) {
          if (err) { return done(err, false); }
    
          if (user) {
            req.user = user; // <= Add this line
            done(null, user);
          } else {
            done(null, false);
          }
        });
      });
    
    那就这样:现在,任何经过 passport.authenticate("jwt", {session: false}) 中间件的路由在成功验证后将会接收到 req.user

这就是全部内容了。


1
谢谢。好的回答 => 为我节省了时间。 - Profess Physics
1
优秀的回答。让我的代码保持整洁并节省了我的时间。 - jimbob
2
根据文档,verify函数只接受两个参数:payloaddone。如果我添加了req会出现错误,你有什么想法吗? - Théo Champion
@ThéoChampion,请查看第一步中的最后一个选项:passReqToCallback: true。请确保将其包含在您的jwtOptions中,然后您现在可以调用verify作为verify(req,payload,done) - Samson Maosa

4
你在testAuth路由中使用了passport.authorize,这是为已经登录并有会话信息的用户准备的。由于你没有使用会话存储,所以没有持久化的req.user对象,因此应该在所有路由上使用passport.authenticatehttp://passportjs.org/docs/authorize

尽管下面的答案得票更多,但这似乎是正确的答案。您应该为每个请求(除WebSockets之外)发送“Bearer token”并在所有路由上使用passport.authenticate('jwt', { session: false },就像Carlos所提到的那样。 - kuzey beytar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接