TypeError:[function]不是Passport本地策略中的函数

时间:2019-09-17 14:53:09

标签: mongodb express passport.js

我正在尝试通过Passport.js在本地对用户进行身份验证,同时又不保留会话并使用自己的JWToken。

我正在关注本教程:  Learn using JWT with Passport authentication

同时也阅读Passport.js文档。我不知道出了什么问题,但是护照似乎并没有注意到某些功能确实是功能。

我有一个加载功能,可以根据特定条件从数据库(mongo)中选择一个用户(用户可以使用电子邮件或电话号码登录)。

  load: function(options, cb) {
    options.select = options.select || 'email phone';
    return this.findOne(options.criteria)
      .select(options.select)
      .exec(cb);
  }

我正在打电话给我的护照。请在我的路线中进行身份验证:

// Controllers //
const Users = require('../../app/controllers/users');  
...
...  
app.post('/api/login', passport.authenticate('local', { failureRedirect: '/api/login' }), Users.login);

这是我的本地策略:

const mongoose = require('mongoose');
const User = mongoose.model('User');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
  {
  usernameField: 'email',
  phoneField: 'phone',
  passwordField: 'password',
  session: false
  }, 

  function(email, phone, password) {//cb == callback
    const options = {
      criteria: { email: email, phone: phone },
      select: 'name username email hashed_password salt'    
    };

    User.load(options, function(err, user) {

      if (err || !user){
        return res.status(400).json({
          type: 'failure',
          message: "User creation failed",  
          data: [err]
        });
      };

      if (!user.authenticate(password)) {
        return res.status(400).json({
          type: 'failure',
          message: "User creation failed",  
          data: [err]
        });
      };

      req.login(user, {session: false}, (err) => {
         if (err) {
             res.send(err);
         }

         // generate a signed son web token with the contents of user object and return it in the response
         const token = jwt.sign(user.id, 'your_jwt_secret');
         return res.json({user, token});
      });
    });
  }
));

我遇到以下错误:

TypeError: res.status is not a function

在尝试与被申请人从护照取回东西之前。我曾尝试像本教程中那样使用cb(callback)来做到这一点,但是我仍然遇到相同的错误。

在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

在实施Passport的本地策略时会遇到一些问题,这会引起问题。

当Passport的本地启动方式仅接受一个字段时,您尝试使用两个字段作为用户名。 (请参阅:http://www.passportjs.org/packages/passport-local/

 function(username, password, done){}

如果您想同时使用它们作为用户名,则可能需要考虑创建自己的自定义策略。这将进行更深入的介绍,但是您可以在Passport Github页面(https://github.com/jaredhanson/passport-strategy)上开始学习

第二个问题是您正在尝试让Passport在本地策略中发送响应,这不是本来打算做的。相反,您应该将错误传递并返回值到Passport的done()函数,该函数将对其进行相应的处理。

以下是您的本地策略应为以下示例:

passport.use(
    new LocalStrategy(async (email, phone, password, done) => {
        const options = {
            criteria: { email, phone },
            select: 'name username email hashed_password salt',
        };

        try {
            const user = await User.load(options);

            /**
             * If null is returned meaning there was no user found, send the done call
             * with the false flag. This tells passport to redirect to the failure URL.
             */
            if (!user) {
                return done(null, false);
            }

            /**
             * If the user's password is incorrect, also return the done function with the false
             * flag. This tells passport to redirect to the failure URL.
             */
            if (!user.authenticate(password)) {
                return done(null, false);
            }

            /**
             * If a user is found and their password is verified, send the user object to
             * the done function. This will tell Passport to call the next middelware attaching
             * the user object.
             */
            return done(null, user);
        } catch (err) {
            /**
             * If there is an error with the DB call, return generic message
             * for security purposes.
             */
            return done('There was an internal server error.');
        }
    })
);

以及加载函数应如下所示的示例:

load: options => {
    return new Promise(async (resolve, reject) => {
        options.select = options.select || 'email phone';
        try {
            const user = await this.findOne(options.criteria)
                .select(options.select)
                .exec();

            resolve(user);
        } catch (err) {
            reject(err);
        }
    });
};

作为一般的最佳实践,我将您的回调更改为较新的Promise方法(https://developers.google.com/web/fundamentals/primers/promises)。

这应该以您打算使用Passport的方式工作。