在 mongodb 中将多个 passportjs 提供程序保存到同一个用户文档中

Saving multiple passportjs providers into same user document in mongodb

我遇到了无法解决的问题。我正在使用 nodejs 开发一个应用程序,使用 mongodb、expressjs 和 passportjs 作为我的身份验证中间件。

我目前有3个策略:facebook、twitter和instagram。我想要实现的是,当用户第一次登录时,如果用户使用一种策略登录并使用另一种策略登录,则将配置文件保存到同一个 mongodb 用户文档中。

这是我的 auth/index.js:

require('./local/passport').setup(User, config);
require('./facebook/passport').setup(User, config);
require('./twitter/passport').setup(User, config);
require('./instagram/passport').setup(User, config);

var router = express.Router();

router.use('/local', require('./local'));
router.use('/facebook', require('./facebook'));
router.use('/twitter', require('./twitter'));
router.use('/instagram', require('./instagram'));

例如,这是我的 auth/twitter/index.js

var router = express.Router();

router
  .get('/', passport.authenticate('twitter', {
    failureRedirect: '/',
    session: false
  }))
  .get('/callback', passport.authenticate('twitter', {
    failureRedirect: '/',
    session: false
  }), auth.setTokenCookie);

  module.exports = router;

但是我如何将 mongodb _id 传递给此 auth/twitter/passport.js 以便将其传递给猫鼬查询并更新用户?像制作 POST 到 auth/twitter 并访问 req.user._id 之类的东西?我不知道该怎么做。

exports.setup = function (User, config) {
  var passport = require('passport');
  var TwitterStrategy = require('passport-twitter').Strategy;
  var TwitterApi = require('twitter');

  passport.use(new TwitterStrategy({
    consumerKey: process.env.TWITTER_CONSUMER_KEY,
    consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
    callbackURL: config.twitter.callbackURL
  },
  function(token, tokenSecret, profile, done) {
    User.findOne({
      'twitter.id_str': profile.id
    }, function(err, user) {
      if (err) {
        return done(err);
      }
      if (!user) {
        user = new User({
          role: 'user',
[...]

非常感谢。

编辑: 这就是我设置 cookie 的方式:

function setTokenCookie(req, res) {
  if (!req.user) return res.json(404, { message: 'Something went wrong,       please try again.'});
  var token = signToken(req.user._id, req.user.role);
  res.cookie('token', JSON.stringify(token));
  res.redirect('/');
}

和 signToken 函数:

function signToken(id) {
  return jwt.sign({ _id: id }, config.secrets.session, {     expiresInMinutes: 60*24*30 });
}

为什么 req.user 和 req.session 在我的策略中总是空的?

编辑2:

我想我可以在调用策略之前使用 auth.isAuthenticated() 函数将用户附加到请求。我所做的是:

router
  .get('/', auth.isAuthenticated(), passport.authenticate('twitter',  auth.isAuthenticated, {
    failureRedirect: '/',
    session: false
  }))
  .get('/callback', auth.isAuthenticated(),  passport.authenticate('twitter', {
    failureRedirect: '/',
    session: false
  }), auth.setTokenCookie);

但现在我遇到了这个问题:

UnauthorizedError: No Authorization header was found

我对 auth/twitter 的请求来自 $window.location。似乎这并没有将用户对象附加到请求,因为当我使用 isAuthenticated() 进行 GET 或 POST 时,用户对象被正确传递。这是我的 isAuthenticated() 函数:

function isAuthenticated() {
  return compose()
    // Validate jwt
    .use(function(req, res, next) {
      // allow access_token to be passed through query parameter as well
      if(req.query && req.query.hasOwnProperty('access_token')) {
        req.headers.authorization = 'Bearer ' + req.query.access_token;
      }
      validateJwt(req, res, next);
    })
    // Attach user to request
    .use(function(req, res, next) {
       User.findById(req.user._id, function (err, user) {
        if (err) return next(err);
        if (!user) return res.send(401);

        req.user = user;
        next();
      });
});

}

您可以在定义通行证策略时将passReqToCallback设置为true。它将发出当前请求,因此当前登录的用户可用于您的回调函数。

exports.setup = function (User, config) {
  var passport = require('passport');
  var TwitterStrategy = require('passport-twitter').Strategy;
  var TwitterApi = require('twitter');

  passport.use(new TwitterStrategy({
    consumerKey: process.env.TWITTER_CONSUMER_KEY,
    consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
    callbackURL: config.twitter.callbackURL,
    passReqToCallback: true
  },
  function(req, token, tokenSecret, profile, done) {
    User.findOne({
      'twitter.id_str': profile.id
    }, function(err, user) {

      if (err) return done(err);

      if (!user) {

        if (req.user) {
[...]

仅供参考,我刚刚在我的策略中处理了解码 JWT 令牌的问题。我不知道这是否是一个好的做法,但问题是如果请求是用 $window.location.href 发出的,我没有让我的用户附加到请求 所以在我的策略中,我读取 cookie 并即时解码它以在数据库中搜索用户。

谢谢。