【问题标题】:REST API is not changing users according to Passport JWT Token in header?REST API 没有根据标头中的 Passport JWT 令牌更改用户?
【发布时间】:2016-11-19 21:00:31
【问题描述】:

所以我有一个用 Node.JS、MongoDB 和 Express 编写的 REST API。我正在使用 passport 和 passport-jwt 来使用 JSON Web 令牌进行身份验证,但是当我为不同的用户帐户使用不同的令牌时,请求每次都保存同一个用户。

这是我在 routes.js 中的身份验证端点:

// Authenticate the user and get a JSON Web Token to include in the header of future requests.
  apiRoutes.post('/authenticate', function(req, res) {
    User.findOne({
      email: req.body.email
    }, function(err, user) {
      if (err) throw err;

      if (!user) {
        res.send({ success: false, message: 'Authentication failed. User not found.' });
      } else {
        // Check if password matches
        user.comparePassword(req.body.password, function(err, isMatch) {
          if (isMatch && !err) {
            // Create token if the password matched and no error was thrown
            var token = jwt.sign(user, config.secret, {
              //expiresIn: 10080 // in seconds
            });
            res.json({ success: true, token: 'JWT ' + token, _id: user._id });
          } else {
            res.send({ success: false, message: 'Authentication failed. Passwords did not match.' });
          }
        });
      }
    });
  });

因此,如果用户凭据在数据库中匹配,它会创建一个新令牌并返回它。然后我将该令牌放入此端点的标头中:

// GET user
  apiRoutes.get('/users', passport.authenticate('jwt', { session: false }), function(req, res) {
    res.json(req.user);
  }); 

我可以每次都验证一个新用户并获得不同的令牌,但是 /users 端点总是返回同一个用户。其他一切都在 API 中工作,在注册新用户时数据库正在更新,并且正在返回其他内容,但即使使用不同的令牌,相同的用户也会从护照中返回。我知道我在 Postman 中以正确的方式放置了标头,其中包含 Authorization 的键和前面带有 JWT 的令牌的值,但我不明白为什么会这样。

如果重要的话,这是我的 passport.js:

var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var User = require('../models/user');
var config = require('./main');

// Setup work and export for the JWT passport strategy
module.exports = function(passport) {
  var opts = {};
  opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
  opts.secretOrKey = config.secret;
  passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
    User.findOne({id: jwt_payload.id}, function(err, user) {
      if (err) {
        return done(err, false);
      }
      if (user) {
        done(null, user);
      } else {
        done(null, false);
      }
    });
  }));
};

有什么想法吗?

【问题讨论】:

    标签: node.js mongodb express passport.js express-jwt


    【解决方案1】:

    Mongo 在文档 ID 前使用“_”。而不是 User.findOne({id: jwt_payload.id} 你应该有 User.findOne({_id: jwt_payload._id} 这应该可以解决问题。

    var JwtStrategy = require('passport-jwt').Strategy;
    var ExtractJwt = require('passport-jwt').ExtractJwt;
    var User = require('../models/user');
    var config = require('./main');
    
    // Setup work and export for the JWT passport strategy
    module.exports = function(passport) {
      var opts = {};
      opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
      opts.secretOrKey = config.secret;
      passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
        User.findOne({_id: jwt_payload._id}, function(err, user) {
          if (err) {
            return done(err, false);
          }
          if (user) {
            done(null, user);
          } else {
            done(null, false);
          }
        });
      }));
    };

    【讨论】:

      【解决方案2】:

      所以我发现它显示了用户文档中的第一个条目,因为 JWT 太大了。因此,我更改了身份验证路由,使 JWT 仅包含用户的 id 和用户名,如下所示:

      apiRoutes.post('/authenticate', function(req, res) {
          User.findOne({
            email: req.body.email
          }, function(err, user) {
            if (err) throw err;
      
            if (!user) {
              res.send({ success: false, response: 'Authentication failed. User not found.' });
            } else {
              // Check if password matches
              user.comparePassword(req.body.password, function(err, isMatch) {
                if (isMatch && !err) {
                  // Create token if the password matched and no error was thrown
                  var token = jwt.sign({id: user._id, username: user.username }, config.secret, {
                    expiresIn: 10080 // in seconds
                  });
                  res.json({ success: true, response: 'Authentication succeeded! User found.', token: 'JWT ' + token});
                } else {
                  res.send({ success: false, response: 'Authentication failed. Passwords did not match.' });
                }
              });
            }
          });
        });  
      

      【讨论】:

        【解决方案3】:

        在 5.5.4 版本的 jwt.sign 之后 Payload 有了更多的数据,现在 _id 是 payload 下 _doc 的一部分。

        正如上面所说的“SamuelDuke”是正确的,只需更改为 jwt_payload._doc._id。 请参阅下面的更新代码。

        var JwtStrategy = require('passport-jwt').Strategy;
        var ExtractJwt = require('passport-jwt').ExtractJwt;
        var User = require('../models/user');
        var config = require('./main');
        
        // Setup work and export for the JWT passport strategy
        module.exports = function(passport) {
          var opts = {};
          opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
          opts.secretOrKey = config.secret;
          passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
            User.findOne({_id: jwt_payload._doc._id}, function(err, user) {
              if (err) {
                return done(err, false);
              }
              if (user) {
                done(null, user);
              } else {
                done(null, false);
              }
            });
          }));
        };
        

        【讨论】:

          猜你喜欢
          • 2021-12-29
          • 2017-03-04
          • 2019-07-25
          • 1970-01-01
          • 2020-08-27
          • 2020-06-09
          • 1970-01-01
          • 2017-07-02
          • 2021-05-14
          相关资源
          最近更新 更多