使用passport.js 进行身份验证与语法混淆?

jdo*_*dvr 3 javascript node.js express passport.js

在passport.js 中有一些我不明白的东西。

1.

var passport = require('passport')
  , LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findOne({ username: username }, function (err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
  }
));
Run Code Online (Sandbox Code Playgroud)

nulldone()函数中代表什么。它似乎总是第一个参数,我对它的实际作用感到困惑?

2.

passport.serializeUser(function(user, cb) {
  cb(null, user);
});

passport.deserializeUser(function(obj, cb) {
  cb(null, obj);
});
Run Code Online (Sandbox Code Playgroud)

序列化和反序列化有什么作用?当会话存储在浏览器中时,是否在登录后调用序列化?反序列化是在访问页面时,会话在服务器上反序列化以验证该用户?

最后又是什么null参数cb(null, user);

nem*_*035 5

  1. 在 done() 函数中 null 代表什么。它似乎总是第一个参数,我对它的实际作用感到困惑?

    • cb(null, user) 中的空参数又是什么;

按照惯例,NodeJS 使用错误优先回调,这意味着回调函数的第一个参数始终是错误对象。如果您没有任何错误,则传入null. 换句话说,如果错误参数是null,则操作成功,如果错误参数不是null,则发生错误。这适用于您询问的所有示例。如果您查看代码,您会发现您已经在利用它:

User.findOne({ username: username }, function (err, user) {
  if (err) { 
    // Error happened and passed as first argument
    return done(err); 
  } 

  // ...

  // no error so we pass in null
  return done(null, user);
Run Code Online (Sandbox Code Playgroud)

此外,Passport 有其身份验证过程的约定,正如他们的文档所说:

如果凭据有效,则验证回调将调用done以向通过身份验证的用户提供 Passport。如果凭据无效(例如,如果密码不正确),done则应使用 false 而不是用户调用以指示身份验证失败。

这就是你在这里所做的:

User.findOne({ username: username }, function (err, user) {

  // ...

  if (!user) {
    return done(null, false, { message: 'Incorrect username.' });
  }
  if (!user.validPassword(password)) {
    return done(null, false, { message: 'Incorrect password.' });
  }

  // ...
Run Code Online (Sandbox Code Playgroud)
  1. 序列化和反序列化有什么作用?当会话存储在浏览器中时,是否在登录后调用序列化?反序列化是在访问页面时,因此会话在服务器上反序列化以验证该用户?

好吧,Passport 的文档说:

如果身份验证成功,将通过用户浏览器中设置的 cookie 建立和维护会话。每个后续请求将不包含凭据,而是包含标识会话的唯一 cookie。为了支持登录会话,Passport 将在会话中序列化和反序列化用户实例。

这意味着,在用户登录后,serializeUser将调用您传递给回调的用户数据cb

passport.serializeUser(function(user, cb) {
  cb(null, user); // <-- this user object
});
Run Code Online (Sandbox Code Playgroud)

保存在会话存储(通常是浏览器 cookie)中并req.session.passport.user在您的代码中可用。

当用户重新连接到您的页面时(通过刷新或离开并返回),相同的数据将作为deserializeUser要使用的第一个参数传递来检索用户对象。

passport.deserializeUser(function(obj, cb) {
  cb(null, obj); // <-- obj is the same `user` object you used in serializeUser
});
Run Code Online (Sandbox Code Playgroud)

您在这里所做的是将实际user对象传递给回调中serializeUser,然后通过回调中的回调将同一对象传递回deserializeUser。这意味着您将整个用户对象存储在您的 cookie 中,这可以随意播放,但通常不是一个好主意,因为 cookie 存储是有限的,而且用户信息通常很敏感。

执行此操作的典型方法是将用户 ID(而不是整个用户对象)传递给cbinserializeUser以保持会话中存储的数据量较小。当进一步的请求发生时,这个 id 被传递给deserializeUser并用于查找实际的用户对象,通常是从数据库中,该对象将被恢复到req.user.

下面是一个例子:

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});
Run Code Online (Sandbox Code Playgroud)