NodeJs Express-将请求参数传递给护照进行身份验证

时间:2018-10-26 15:44:31

标签: node.js express passport.js

我在理解nodejs语法时遇到问题。我正在尝试自定义护照的错误消息,并且遵循以下代码:

router.get('/', (req, res, next) => {
    passport.authenticate('jwt', {session: false}, function(err, user, info) {
        //do some stuff here

        //if error, return some stuff
        res.json({...}) 

    })(req, res, next)
}

但是在我遵循的教程语法中,router.route是以这种方式制作的:

router.route('/')
    .get(passport.authenticate('jwt', {session: false}, (err, user, info) => {
        //res cannot be found here
        res.json({...}) 

    }), UsersController.index);

由于我具有涉及护照中间件和控制器的这种语法,因此 res.json()变得不确定。如何传递 res,req和next 使用这种语法的参数?

1 个答案:

答案 0 :(得分:1)

好的,所以一般我不会像您想要的那样在身份验证回调中自定义错误消息。首先,如果要这样做,您将在每次身份验证调用中重复一次,其次,这与该中间件无关。

不过,我倾向于集中进行错误处理和消息传递,这是一个较长的讨论。

如果您确实要执行此操作,则需要确保req, res, next在范围内,如下所示:

app.route('/login')
   .get(function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
      if (err) { 
         err.message = 'Incorrect username or password';
         return next(err); 
      }
      if (!user) { return res.redirect('/login'); }
      req.logIn(user, function(err) {
        if (err) { return next(err); }
        return res.redirect('/users/' + user.username);
      });
    })(req, res, next);
});

好的,关于集中化错误处理,我通常采用的方法是创建可根据需要实例化的自定义错误类,然后在错误处理中间件中进行处理。可以轻松地将其应用于身份验证,也可以将其应用于其他任何项目,并且可以随着项目的增长而逐步构建它们,因此并不难。例如,从自定义FailedLoginError开始,我可能会做类似的事情(在ES6语法中,使用较旧的JS语法并不难):

// ./lib/errors/failed-login-error.js
class FailedLoginError extends Error {
  // You could set the message here if you wanted rather than letting the calling code set it
  constructor(error, userMessage) {
    super(error.message);
    this.name = this.constructor.name;
    this.previousError = error;
    this.statusCode = 401;
    this.userMessage = userMessage || 'You provided an incorrect username or password'; 
    Error.captureStackTrace(this, this.constructor);
  }
}

然后,我将创建一个包装Passport设置的自定义中间件,这样我就不必记住每次都使用它了。

// ./lib/middleware/authenticate.js
// Similar to the example above, we have an error that has a 500 status
const ServerError = require('../errors/internal-server-error');
const FailedLoginError = require('../errors/failed-login-error');
module.exports = (req, res, next) => {
  passport.authenticate('jwt', { session: false }, (err, user, info) => {
    // an exception happened trying to do the login
    if (err) return next(new ServerError(err));
    // user was not correct.  Add more info to the error message if you want, like maybe the Username was incorrect or the Token was expired or whatever. 
    if (!user) return next(new FailedLoginError(err));
    // we get here and the user logged in right
    req.logIn(user, (e) => {
      if (e) return next(ServerError(e));
      return res.redirect('/users/' + user.username); // or whatever the right thing is here
    });
  });
});

好,因此,通过该设置,您现在可以设置一些利用您的自定义错误的错误处理中间件:

// ./lib/middleware/error-handler.js
module.exports = (err, req, res, next) {
  // normalize the possibly missing status and userMessages
  err.statusCode = err.statusCode || 500;
  err.userMessage = err.userMessage || 'Something went wrong.';

  // always log something; use something other than console.error if you like
  // note here we're logging the real error message. 
  console.error(`${req.method} ${req.url} - ${err.statusCode} - ${err.message}`);

  // next, give the user something you don't mind them seeing
  res.status(err.statusCode).send(err.userMessage);
};

现在将所有内容放在一起,您的应用程序代码将简化为以下形式:

const errorHandler = require('./lib/middleware/error-handler');
const authenticate = require('./lib/middleware/authenticate');
// other requires as needed.

app.use(errorHandler);

app.route('/login')
   .all(authenticate)
   .get((req, res, next) => {
     // whatever you want to do here, it's already got a user and so on.  
   });

我不久前建立了一个使用此模式的库,并创建了一堆通用的HTTP错误类。它可能需要进行更新,但可能会给您一些启发。 https://github.com/pvencill/praeter