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

Posted

技术标签:

【中文标题】NodeJs Express - 将请求参数传递给护照身份验证【英文标题】:NodeJs Express - Passing request parameter to passport authenticate 【发布时间】:2018-10-26 15:44:31 【问题描述】:

我在理解 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】:

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

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

如果您真的想这样做,那么您需要确保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

【讨论】:

对我来说,集中错误处理和消息传递听起来是最好的解决方案。你介意分享一下你会怎么做吗? @muffin 添加了有关按要求集中错误处理的信息。 谢谢,这已经很好地实现和解释了

以上是关于NodeJs Express - 将请求参数传递给护照身份验证的主要内容,如果未能解决你的问题,请参考以下文章

如何将参数传递给 Express post HTTP 方法?

定义后无法将可选参数传递给express

如何将参数传递给 Express JS 中的中间件函数?

使用 Express 服务器将多个参数传递给 Next.js 自定义 URL

如何将参数传递给 MEAN.js 包的 express.js 服务器端路由。

Redis Lua 脚本 - 如何将数组作为参数传递给 nodejs 中的 Lua 脚本?