了解护照序列化反序列化

时间:2014-12-24 13:22:56

标签: node.js authentication express serialization passport.js

您如何解释Passport对外行人序列化和反序列化方法的工作流程。

  1. 调用user.id之后passport.serializeUser去哪儿了?

  2. 我们正在调用passport.deserializeUser之后它在哪里适合工作流程?

    // used to serialize the user for the session
    passport.serializeUser(function(user, done) {
        done(null, user.id); 
       // where is this user.id going? Are we supposed to access this anywhere?
    });
    
    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        User.findById(id, function(err, user) {
            done(err, user);
        });
    });
    
  3. 我仍然试图绕过它。我有一个完整的工作应用程序,并没有遇到任何类型的错误。

    我只想了解这里究竟发生了什么?

    感谢任何帮助。

3 个答案:

答案 0 :(得分:357)

  
      
  1. user.id在调用passport.serializeUser之后去了哪里?
  2.   

用户ID(作为done函数的第二个参数提供)保存在会话中,稍后用于通过deserializeUser函数检索整个对象。

serializeUser确定用户对象的哪些数据应存储在会话中。 serializeUser方法的结果作为req.session.passport.user = {}附加到会话。例如,它将(因为我们提供用户ID作为密钥)req.session.passport.user = {id: 'xyz'}

  
      
  1. 我们正在调用passport.deserializeUser之后它在哪里适合工作流程?
  2.   

deserializeUser的第一个参数对应于赋予done函数的用户对象的键(参见1.)。因此,您可以借助该密钥检索整个对象。这里的密钥是用户id(密钥可以是用户对象的任何密钥,即名称,电子邮件等)。 在deserializeUser中,该密钥与内存数组/数据库或任何数据资源匹配。

获取的对象作为req.user

附加到请求对象

视觉流程

passport.serializeUser(function(user, done) {
    done(null, user.id);
});              │
                 │ 
                 │
                 └─────────────────┬──→ saved to session
                                   │    req.session.passport.user = {id: '..'}
                                   │
                                   ↓           
passport.deserializeUser(function(id, done) {
                   ┌───────────────┘
                   │
                   ↓ 
    User.findById(id, function(err, user) {
        done(err, user);
    });            └──────────────→ user object attaches to the request as req.user   
});

答案 1 :(得分:18)

对于使用Koa和koa-passport的任何人:

知道在serializeUser方法中设置的用户密钥(通常是该用户的唯一ID)将存储在:

this.session.passport.user

在deserializeUser中设置done(null, user)时,'user'是数据库中的某个用户对象:

this.req.user 要么 this.passport.user

由于某种原因{delerializeUser方法中调用done(null,user)时,{a 1}} Koa上下文永远不会被设置。

因此,您可以在调用app.use(passport.session())之后编写自己的中间件,将其放入this.user中,如下所示:

this.user

如果你不清楚serializeUser和deserializeUser是如何工作的,那就试着在twitter上点击我。 @yvanscher

答案 2 :(得分:3)

Passport 使用 serializeUser 函数将用户数据(成功验证后)保存到会话中。函数 deserializeUser 用于从会话中检索用户数据。

serializeUserdeserializeUser 函数都检查传递给它们的第一个参数,如果它是函数类型,则 serializeUserdeserializeUser 什么都不做,但将这些函数放在之后将调用的函数堆栈(当传递的第一个参数不是函数类型时)。 Passport 需要进行以下设置才能在会话中进行身份验证后保存用户数据:

app.use(session({ secret: "cats" }));
app.use(passport.initialize());
app.use(passport.session());

使用的中间件的顺序很重要。重要的是要了解当新的授权请求开始时会发生什么:

  • 会话中间件创建会话(使用来自 sessionStore 的数据)。

  • passport.initialize_passport 对象分配给请求对象,检查是否存在会话对象,是否存在,并且其中存在字段 passport(如果不存在 - 创建一个),将该对象分配给 session 中的 _passport 字段。最后,它看起来像这样:

    req._passport.session = req.session['passport']
    

    因此,分配给 sessionreq.session.passport 字段 references 对象。

  • passport.sessionuser 中查找 req._passport.session 字段,如果找到,则将其传递给 deserializeUser 函数并调用它。 deserializeUser 函数将 req._passport.session.user 分配给请求对象的 user 字段(如果在 req._passport.session.user 中找到)。这就是为什么,如果我们像这样在 serializeUser 函数中设置用户对象:

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

    然后我们需要解析它,因为它在 JSON 字段中保存为 user

     passport.deserializeUser(function(id, done) {
       // parsed user object will be set to request object field `user`
       done(err, JSON.parse(user));
     });
    

因此,当您设置 Passport 时,首先调用 deserializeUser 函数,将您的回调放入 _deserializers 函数堆栈中。第二次,它将在 passport.session 中间件中调用以将 user 字段分配给请求对象。这也会在分配 passport.deserializeUser() 字段之前触发我们的回调(我们放入 user)。

serializeUser 函数在您设置 Passport 时首先调用(类似于 deserializeUser 函数),但它将用于序列化用户对象以保存在会话中。第二次,它会在 login/logIn (alias) 方法中调用,由 Passport 附加,用于保存会话中的用户对象。 serializeUser 函数还会检查 _serializers 堆栈是否已推送给它的函数(其中一个添加,在我们设置 Passport 时):

passport.serializeUser(function(user, done) ...

并调用它们,然后将用户对象(strignified)或用户 ID 分配给 req._passport.session.user。请务必记住,session 字段直接引用 passport 对象中的 req.session 字段。这样用户在会话中保存(因为 req._passport.session 引用对象 req.session.passport,并且 req._passport.session 在每个传入请求中被 passport.initialize 中间件修改)。 当请求结束时,req.session 数据将存储在 sessionStore 中。

授权成功后,当第二个请求开始时会发生什么:

  • session 中间件从 sessionStore 获取会话,我们的用户数据已保存在其中
  • passport.initialize 检查是否有会话并将 req.session.passport 分配给 req._passport.session
  • passport.session 检查 req._passport.session.user 并将其反序列化。在此阶段(如果 req._passport.session.user 为真),我们将让 req.userreq.isAuthenticated() 返回 true