理解护照序列化反序列化

你如何向外行解释Passport的序列化和反序列化方法的工作流程?

  1. 在调用passport.serializeUser之后,user.id去了哪里?< br >

  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);
    });
    });
    

I'm still trying to wrap my head around it. I have a complete working app and am not running into errors of any kind.

I just wanted to understand what exactly is happening here?

Any help is appreciated.

174912 次浏览
  1. 在调用passport.serializeUser之后,user.id去了哪里?

用户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
});

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

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

this.session.passport.user

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

< p > this.req.userthis.passport.user < / p >

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

所以你可以在调用app.use(passport.session())之后编写自己的中间件,把它放在这里。用户如下:

app.use(function * setUserInContext (next) {
this.user = this.req.user
yield next
})

如果您不清楚serializeUser和deserializeUser是如何工作的,请在twitter上联系我。@yvanscher

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

serializeUserdeserializeUser函数都检查传递给它们的第一个参数,如果它是函数类型,serializeUserdeserializeUser什么都不做,而是将这些函数放在一个函数堆栈中,之后将被调用(当传递的第一个参数不是函数类型时)。 在会话中进行身份验证后,Passport需要以下设置来保存用户数据
app.use(session({ secret: "cats" }));
app.use(passport.initialize());
app.use(passport.session());

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

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

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

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

    因此,session字段参考文献对象,赋值给req.session.passport

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

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

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

     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字段分配给请求对象。这也会在分配user字段之前触发回调(我们放在passport.deserializeUser()中)。

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

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

并调用它们,然后将用户对象(经过标记)或用户id分配给req._passport.session.user。重要的是要记住,session字段直接引用req.session对象中的passport字段。这样,会话中的用户保存(因为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

你可以用这个代码升级旧的序列化和反序列化,请在这个帖子上找到新的解决方案。

        passport.serializeUser(function(user, cb) {
process.nextTick(function() {
cb(null, { id: user.id, username: user.username });
});
});
        

passport.deserializeUser(function(user, cb) {
process.nextTick(function() {
return cb(null, user);
});
});

基本上,我们只是使用序列化器将用户id存储在会话中,当我们需要用户模型实例时,我们使用该用户id在数据库中搜索,这是使用反序列化器完成的。

只要会话是活动的,并且用户通过了身份验证,

req.session.passport.user

将始终对应于用户模型实例。

如果我们不将user-id保存到会话中,如果有重定向,我们将无法知道用户是否已经过身份验证。

一旦用户被验证,req.session.passport.user将被设置。 因此,所有未来的请求都将知道用户已通过身份验证

希望这能简化。