了解护照序列化反序列化

Anu*_*hav 300 authentication serialization node.js express 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);
        });
    });
    
    Run Code Online (Sandbox Code Playgroud)

我仍然试图绕过它.我有一个完整的工作应用程序,并没有遇到任何类型的错误.

我只是想了解这里到底发生了什么?

任何帮助表示赞赏.

A.B*_*A.B 391

  1. user.id去哪儿passport.serializeUser打电话?

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

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

  1. 我们正在呼吁passport.deserializeUser它在哪里适合工作流程?

第一个参数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   
});
Run Code Online (Sandbox Code Playgroud)

  • @Zanko您可以将整个用户对象放入会话数据中,但这通常不是一个好主意,因为它可能有其他副作用.例如,当用户更新他/她的用户名时,您也必须更新会话数据,否则您将因"重命名功能损坏"而获得票证.这是一个相对无害的例子.权限位或相同的敏感数据(Oops ...)也可能发生同样的情况.如果您有重复的数据,基本上会遇到相同的问题.TL; DR - 不要这样做. (6认同)
  • `user.id` 保存为 `req.session.passport.user` 或 `user` 本身保存为 `req.session.passport.user` (4认同)
  • @AB我不明白你对uzay95的建议.所以在我的会话中我只有user._id.但是在每个请求中,我都必须使用该id从数据库中反序列化findUserByID,并将其放入req.user中.如何避免在每次请求时都拨打此类电话? (2认同)
  • 如果我没记错的话,图中的 `req.session.passport.user = {id: '..'}` 部分有点偏离,应该是 `req.session.passport.user = 785352`,其中 `785352` 是 `user.id`。我无法通过控制台记录来证明这一点,但这似乎是有道理的。当您调用 `done(null, user.id);` 时,采用第二个参数 - 在这种情况下为 `user.id` - 并将其分配给 `req.session.passport.user` 是有意义的将其分配给 `req.session.passport.user.id`。因为如果你改为传入 `user` 呢?`req.session.passport.user.id = user` 没有意义。 (2认同)

yva*_*her 18

对于任何使用Koa和koa护照的人:

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

this.session.passport.user

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

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

出于某种原因,this.user当您在deserializeUser方法中调用done(null,user)时,Koa上下文永远不会被设置.

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

app.use(function * setUserInContext (next) {
  this.user = this.req.user
  yield next
})
Run Code Online (Sandbox Code Playgroud)

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


Vad*_*adi 7

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

这两个serializeUserdeserializeUser功能检查传递给他们的第一个参数,如果它的类型的功能,serializeUserdeserializeUser什么也不做,而是把这些功能在堆栈中的功能,将被调用,之后(在传递第一参数的数据类型的功能不是)。Passport 需要以下设置来在会话中进行身份验证后保存用户数据:

app.use(session({ secret: "cats" }));
app.use(passport.initialize());
app.use(passport.session());
Run Code Online (Sandbox Code Playgroud)

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

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

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

    req._passport.session = req.session['passport']
    
    Run Code Online (Sandbox Code Playgroud)

    因此,session字段引用对象,分配给req.session.passport.

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

    passport.serializeUser(function(user, done) {
      done(null, JSON.strignify(user)); 
    });
    
    Run Code Online (Sandbox Code Playgroud)

    然后,我们需要分析它,因为它被保存为JSONuser外地:

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

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

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

passport.serializeUser(function(user, done) ...
Run Code Online (Sandbox Code Playgroud)

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

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

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