【问题标题】:PassportJS serializeUser and deserializeUser execution flowPassportJS serializeUser 和 deserializeUser 执行流程
【发布时间】:2015-05-17 22:46:23
【问题描述】:

我正在使用带 express 的 passportJS 通过本地策略对用户进行身份验证。我看过几篇关于如何设置护照和执行流程的文章。虽然护照的大部分内容都可以通过搜索找到,但用户的序列化和反序列化让我感到困惑。

我了解它用于将用户信息保存在会话中以进行持久登录。我的序列化和反序列化代码是

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

passport.deserializeUser(function(id, done){
    User.findById(id, function(err, user){
        done(err, user);
    });
});

我的问题

1) 谁调用和填充serializeUser 和deserializeUser 的参数?以及它如何访问用户对象?为了理解这一点,我添加了类似

的日志
 passport.serializeUser(function(user, done){
    console.log(arguments.callee.caller);
    done(null, user.id);
});

并在输出中得到 [Function: pass] 谁能解释一下?

2) 我正在使用 mongodb 来存储用户信息。 MongoDB 将 _id 作为文档的默认 id。所以理想情况下,serializeUser 和 deserializeUser 应该使用 user._id 而不是 user.id。但它与用户对象中不可用的 user.id 一起工作正常。这是控制台中打印的用户对象

{ _id: 5505f231b810dbd4098ac76a,
  __v: 0,
  google: {},
  twitter: {},
  facebook: {},
  local:
   { password: '$2a$08$9NGd0xNu0JbWMZ07ufyFRu8guwy147k8IBl5cAC4Y8APOuxreNI32',
     email: 'xxxx@xxx.com' } }

这怎么可能?

3) 执行done 方法后,控制流执行到哪里?

【问题讨论】:

    标签: node.js express mongoose passport.js


    【解决方案1】:

    您正在使用基于 cookie 的身份验证。为了回答你,也许是一个对一切都很陌生的人,我会尽量做到非常详细。所以这里有一个场景......

    • 用户进来并说:“我想登录,这是我的 Google 个人资料。”
    • 然后我们的服务器说:“好的,我们将运行我们创建的 google 策略回调函数,并处理我们刚刚从您那里获得的配置文件......”

    让我们想象一下,这个用户之前已经登录到我们的应用程序,所以我们的用户集合中有一条记录与这个配置文件匹配,所以服务器说:“看起来你和 user123 有相同的谷歌配置文件 ID(我们已保存在我们的数据库中)。我需要给您一些识别令牌,表明您毫无疑问是:'user123',并且此令牌将在对我们的服务器发出的任何后续请求中识别您”

    此时,为了生成小标记或小标识信息,我们将定义一个名为“serializeUser”的函数。 serializeUser 将通过我们在最后一步中刚刚获取的用户模型被护照自动调用。因此,为了解释,我们将使用该用户模型来生成我们的识别用户信息,然后我们将将该识别信息传递回护照,以便护照可以自动将那个小令牌填充到用户的 cookie 给我们。

    现在,一旦用户决定他们想要发出某种类型的后续请求,例如帖子列表或消息列表或其他任何内容,从浏览器返回到我们的服务器,该请求的 cookie 将是由浏览器自动添加到请求中,passport 将从 cookie 中获取识别信息,然后将其传递给名为“deserializeUser”的第二个函数,在该函数中,我们将获取该识别令牌并将其转换回唯一标识此用户的用户模型。

    总结一下……

    在第一个过程 (seralizeUser) 中,“user”是一个用户模型实例(如果使用 mongoose,则为 mongoose 模型)...我们所做的就是将该模型转换为 id。

    在第二个过程(deserializeUser)中,我们正在做完全相反的事情,将 id 转换为 mongoose 模型实例。为此,我们必须使用我们数据库中存在的所有不同用户搜索或查询我们的 big'ol 集合(使用 findById),在我们找到那个非常特定的用户之后,我们将调用'done'用户,这意味着我们将返回该用户。

    【讨论】:

      【解决方案2】:

      经过长时间的搜索,我找到了这个article ,它非常清楚地解释了身份验证流程。

      • 对于 serializeUser:
      1. 当用户提交登录表单时,对 /login 的 POST 请求是 导致执行 passport.authenticate 我们设置的中间件。
      2. 因为该路由的身份验证中间件配置为 处理本地策略,护照将调用我们的 实施当地战略。
      3. Passport 采用 req.body.username 和 req.body.password 和 将其传递给本地策略中的验证函数。
      4. 现在我们做我们的事情:从数据库中加载用户并检查 如果给定的密码与数据库中的密码匹配。
      5. 如果一切正常并且我们希望用户登录,我们调用 done(null, user)。
      6. 调用 done 将使流程跳转回 passport.authenticate。它通过了错误、用户和其他 info 对象(如果已定义)。
      7. 如果用户被传递,中间件将调用 req.login (a 护照功能附加到请求)。
      8. 这将调用我们定义的 passport.serializeUser 方法 早一点。
      • 对于反序列化用户:
      1. Express 加载会话数据并将其附加到请求中。由于护照将序列化的用户存储在会话中
      2. passport.session 中间件是一个将加载的 Passport 策略 如果找到序列化的用户对象,则将用户对象添加到 req.user 在服务器中。
      3. passport.initialize 在请求中被调用,它会找到连接到会话的 passport.user。接下来,passport.session 是 调用。
      4. passport.session 中间件调用 passport.deserializeUser 我们已经 设置。将加载的用户对象作为 req.user 附加到请求。

      希望对你有帮助。

      【讨论】:

      • 在花费了将近 30 个小时浏览无数的代码排列之后,deserializeUser 从未被触发。
      • 这是一篇不错的文章,但你丢掉了一篇重要的文章,对于那些为这些调用的功能而苦恼的人。 8. This will call our passport.serializeUser method we've defined earlier. This method can access the user object we passed back to the middleware. It's its job to determine what data from the user object should be stored in the session. The result of the serializeUser method is attached to the session as req.session.passport.user = { // our serialised user object // }.
      【解决方案3】:

      由于您使用的是 PassportJS,所以我认为您一定对它的工作原理有所了解。因此,我将添加更多信息,我认为这可以消除您的疑问。

      护照配置涉及三部分:

      1. 身份验证策略
      2. 应用中间件
      3. 会话

      您的问题的答案在于第三部分,会话。

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

      根据您的实现,只有用户 ID 被序列化到会话中,从而保持会话中存储的数据量很小。后续收到请求时,使用此ID查找用户,恢复为req.user

      在护照中,我们可以选择编写自己的序列化和反序列化逻辑,以便我们可以选择任何合适的数据库,而不受严格规则的约束。

      总而言之,认证成功后,用户对象被序列化并存储在会话中,如果你调用req.user,那么你将能够检索到相同的用户对象。

      【讨论】:

      • 我明白你在说什么。但我的疑问有些不同。 :)
      • 嗨,真的很好的解释,但这是否可以更改 serializeUser mid-session 中的信息,因为这是在用户登录时设置的。所以我想要在 cookie 中设置两件事但有一件事是动态的
      猜你喜欢
      • 2016-03-24
      • 1970-01-01
      • 1970-01-01
      • 2015-04-01
      • 2019-02-08
      • 2012-07-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-06
      相关资源
      最近更新 更多