简体   繁体   English

Express Passport (node.js) 错误处理

[英]Express Passport (node.js) error handling

I've looked at how error handling should work in node via this question Error handling principles for Node.js + Express.js applications?我已经通过这个问题Error handling principles for Node.js + Express.js applications? 研究了错误处理应该如何在节点中工作? , but I'm not sure what passport's doing when it fails authentication. ,但我不确定护照在身份验证失败时在做什么。 I have the following LocalStrategy:我有以下 LocalStrategy:

passport.use(new LocalStrategy({ usernameField: 'email', passwordField: 'password' },
  function(email, password, next) {
 
    User.find({email: UemOrUnm}, function(err, user){
      if (err) { console.log('Error > some err'); return next(err); }
      if (!user) { console.log('Error > no user'); return next('Incorrect login or password'); } 

      if (password != user.password) {
        return next(Incorrect login or password);
      }
      return next(null, user);
    });
  }
));

After I see 'Error > some err' console printout, nothing else happens.在我看到“Error > some err”控制台打印输出后,没有其他事情发生。 I would think it should continue on the the next path with an error parameter, but it doesn't seem to do that.我认为它应该在带有错误参数的下一条路径上继续,但它似乎并没有这样做。 What's going on?这是怎么回事?

The strategy-implementation works in conjunction with passport.authenticate to both authenticate a request, and handle success/failure.策略实现与passport.authenticate结合使用以验证请求并处理成功/失败。

Say you're using this route (which is passed an e-mail address and a password):假设您正在使用此路由(通过电子邮件地址和密码):

app.post('/login', passport.authenticate('local', {
  successRedirect: '/loggedin',
  failureRedirect: '/login', // see text
  failureFlash: true // optional, see text as well
});

This will call the code in the strategy, where one of three conditions can happen:这将调用策略中的代码,其中可能发生以下三种情况之一:

  1. An internal error occurred trying to fetch the users' information (say the database connection is gone);尝试获取用户信息时发生内部错误(假设数据库连接消失); this error would be passed on: next(err) ;将传递此错误: next(err) ; this will be handled by Express and generate an HTTP 500 response;这将由 Express 处理并生成 HTTP 500 响应;
  2. The provided credentials are invalid (there is no user with the supplied e-mail address, or the password is a mismatch);提供的凭据无效(没有用户具有提供的电子邮件地址,或者密码不匹配); in that case, you don't generate an error, but you pass a false as the user object: next(null, false) ;在这种情况下,您不会生成错误,而是将false作为用户对象传递: next(null, false) this will trigger the failureRedirect (if you don't define one, a HTTP 401 Unauthorized response will be generated);这将触发failureRedirect (如果您没有定义,则会生成 HTTP 401 Unauthorized 响应);
  3. Everything checks out, you have a valid user object, so you pass it along: next(null, user) ;一切都检查出来了,你有一个有效的用户对象,所以你传递它: next(null, user) ; this will trigger the successRedirect ;这将触发successRedirect

In case of an invalid authentication (but not an internal error), you can pass an extra message along with the callback:如果身份验证无效(但不是内部错误),您可以随回调传递额外的消息:

next(null, false, { message : 'invalid e-mail address or password' });

If you have used failureFlash and installed the connect-flash middleware , the supplied message is stored in the session and can be accessed easily to, for example, be used in a template.如果您使用了failureFlash安装了 connect-flash 中间件,则提供的消息将存储在会话中,并且可以轻松访问,例如,在模板中使用。

EDIT: it's also possible to completely handle the result of the authentication process yourself (instead of Passport sending a redirect or 401):编辑:也可以自己完全处理身份验证过程的结果(而不是 Passport 发送重定向或 401):

app.post('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) {
      return next(err); // will generate a 500 error
    }
    // Generate a JSON response reflecting authentication status
    if (! user) {
      return res.send({ success : false, message : 'authentication failed' });
    }
    // ***********************************************************************
    // "Note that when using a custom callback, it becomes the application's
    // responsibility to establish a session (by calling req.login()) and send
    // a response."
    // Source: http://passportjs.org/docs
    // ***********************************************************************
    req.login(user, loginErr => {
      if (loginErr) {
        return next(loginErr);
      }
      return res.send({ success : true, message : 'authentication succeeded' });
    });      
  })(req, res, next);
});

What Christian was saying was you need to add the function Christian 所说的是你需要添加函数

req.login(user, function(err){
  if(err){
    return next(err);
  }
  return res.send({success:true});
});

So the whole route would be:所以整个路线将是:

app.post('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) {
      return next(err); // will generate a 500 error
    }
    // Generate a JSON response reflecting authentication status
    if (! user) {
      return res.send(401,{ success : false, message : 'authentication failed' });
    }
    req.login(user, function(err){
      if(err){
        return next(err);
      }
      return res.send({ success : true, message : 'authentication succeeded' });        
    });
  })(req, res, next);
});

source: http://passportjs.org/guide/login/来源: http : //passportjs.org/guide/login/

You need to add req.logIn(function (err) { });您需要添加req.logIn(function (err) { }); and do the success redirect inside the callback function并在回调函数中执行成功重定向

Some time has passed and now the most right code will be:一段时间过去了,现在最正确的代码是:

  passport.authenticate('local', (err, user, info) => {
    if (err) {
      return next(err); // will generate a 500 error
    }
    // Generate a JSON response reflecting authentication status
    if (!user) {
      return res.status(401).send({ error: 'Authentication failed' });
    }
    req.login(user, (err) => {
      if (err) {
        return next(err);
      }
      return res.status(202).send({ error: 'Authentication succeeded' });    
    });
});

I found this thread very useful!我发现这个线程非常有用!

https://github.com/jaredhanson/passport-local/issues/2 https://github.com/jaredhanson/passport-local/issues/2

You could use this to return error and render it in form.您可以使用它来返回错误并以形式呈现。

app.post('/login',
  passport.authenticate('local', { successRedirect: '/home', failWithError: true }),
  function(err, req, res, next) {
    // handle error
    return res.render('login-form');
  }
);

This is what I got after console.log(req) at the failler route.这是我在 failler 路由的console.log(req)之后得到的。

const localStrategy = new LocalStrategy({ usernameField: "email" }, verifyUser);

passport.use(localStrategy);

const authenticateWithCredentials = passport.authenticate("local", {
  failureRedirect: "/api/auth/login-fail",
  failureMessage: true,
});

validation method find your user from db and throw error to the cb if there is any验证方法从 db 中找到您的用户,如果有任何错误,则向 cb 抛出错误

const verifyUser = async (email, password, cb) => {
  const user = await User.findOne({ email });
  if (!user) return cb(null, false, { message: "email/password incorrect!" });

  const isMatched = await user.comparePassword(password);
  if (!isMatched)
    return cb(null, false, { message: "email/password incorrect!" });

  cb(null, {
    id: user._id,
    email,
    name: user.name,
  });
};

now setup your route现在设置你的路线

router.post("/sign-in", authenticateWithCredentials,(req, res) => {
  res.json({user: req.user})
});

router.get("/login-fail", (req, res) => {
  let message = "Invalid login request!";

  // if you are using typescript cast the sessionStore to any 
  const sessions = req.sessionStore.sessions || {};
  for (let key in sessions) {
    const messages = JSON.parse(sessions[key])?.messages;
    if (messages.length) {
      message = messages[0];
      break;
    }
  }

  res.status(401).json({ error: message });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM