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

Where does user.id go after passport.serializeUser has been called? We are calling passport.deserializeUser right after it where does it fit in the workflow? // 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); }); });

我还没想明白呢。我有一个完整的工作应用程序,没有遇到任何类型的错误。

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

任何帮助都是感激的。


当前回答

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

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

其他回答

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

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

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

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

req.session.passport.user

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

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

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

希望这能简化。

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

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

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

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

session middleware creates session (using data from the sessionStore). passport.initialize assigns _passport object to request object, checks if there's a session object, and if it exists, and field passport exists in it (if not - creates one), assigns that object to session field in _passport. At the end, it looks, like this: req._passport.session = req.session['passport'] So, session field references object, that assigned to req.session.passport. passport.session looks for user field in req._passport.session, and if finds one, passes it to deserializeUser function and calls it. deserializeUser function assigns req._passport.session.user to user field of request object (if find one in req._passport.session.user). This is why, if we set user object in serializeUser function like so: passport.serializeUser(function(user, done) { done(null, JSON.strignify(user)); }); We then need to parse it, because it was saved as JSON in user field: 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中被调用。会话中间件将用户字段分配给请求对象。这也会在分配user字段之前触发回调(我们放在passport.deserializeUser()中)。

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

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

并调用它们,然后将用户对象(经过标记)或用户id分配给req._passport.session.user。重要的是要记住session字段在req中直接引用passport字段。会话对象。这样用户就保存在会话中了(因为req._passport. conf。会话引用对象req.session。Passport和req._passport。会话在每个传入请求中通过护照进行修改。初始化中间件)。 当请求结束时,请求。会话数据将存储在sessionStore中。

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

会话中间件从sessionStore获取会话,我们的用户数据已经保存在sessionStore中 护照。初始化检查是否有会话,并将req.session.passport分配给req._passport.session 护照。会话检查req._passport.session。用户并反序列化它。在此阶段(如果req._passport.session. conf。用户是真实的),我们将有需求。req.isAuthenticated()返回true。

对于任何使用可可豆和可可豆护照的人:

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

this.session.passport.user

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

this.req.user 或 this.passport.user

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

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

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

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

用户在哪里。我去拿护照。serializeUser是否被调用?

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

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

我们在它后面调用passport。deserializeuser它在工作流中的位置是什么?

deserializeUser的第一个参数对应给done函数的user对象的键(见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   
});