REST API 没有根据标头中的 Passport JWT 令牌更改用户?
Posted
技术标签:
【中文标题】REST API 没有根据标头中的 Passport JWT 令牌更改用户?【英文标题】:REST API is not changing users according to Passport JWT Token in header? 【发布时间】: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);
);
));
;
有什么想法吗?
【问题讨论】:
【参考方案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);
);
));
;
【讨论】:
以上是关于REST API 没有根据标头中的 Passport JWT 令牌更改用户?的主要内容,如果未能解决你的问题,请参考以下文章
我应该通过 HTTP 标头或将正文作为 JSON 传递到 REST Api 吗?
是否使用 If-Modified-Since 标头将资源集合过滤为仅 REST API 中最近的资源集合被视为有效方法?