19

我是否实现了序列化和反序列化?

RedisStore 设置为我与 Express 的会话存储。这是否意味着我没有实现序列化和反序列化?它会自动发生吗?

当我不实施这些方法时,我收到以下 Express 错误 - 500 错误:无法将用户序列化到会话中。当我实现它们时,我不确定在反序列化中放入什么。

下面的代码似乎可以工作,但会话没有持续。每次访问该网站时,我都需要登录。

NodeJS + Passport + RedisStore 的任何地方都有一个很好的例子吗?

var sessionStore = new RedisStore({
                                        host: rtg.hostname,
                                        port: rtg.port,
                                        db: redisAuth[0],
                                        pass: redisAuth[1]
                                      });

passport.use(new ForceDotComStrategy({
    clientID: clientId,
    clientSecret: clientSecret,
    callbackURL: myurl
},
function(token, tokenSecret, profile, done) {
    console.log(profile);
    return done(null, profile);
  }
));

appSecure.configure('production', function(){
appSecure.use(allowCrossDomain);
appSecure.use(express.cookieParser(expressSecret));
appSecure.use(express.bodyParser());
appSecure.use(express.methodOverride());
appSecure.set('port', port); 
appSecure.use(express.session({ secret: expressSecret, store: sessionStore, key:'expressSid', cookie: { maxAge : 604800, domain:'.domain.com'}})); 
appSecure.use(passport.initialize());
appSecure.use(passport.session());
appSecure.use(appSecure.router);
appSecure.use(express.static(__dirname + '/public'));
appSecure.use(express.errorHandler());
});

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

passport.deserializeUser(function( user, done ) {
    done( null, user );
});
4

3 回答 3

47

如果您使用会话,则必须为护照提供序列化和反序列化功能。将 Redis 实现为会话存储与护照的实现方式无关,它只处理会话数据的存储位置。

使用护照实施会话

正如我所说,必须向护照提供序列化和反序列化功能才能使会话正常工作。

serialize函数的目的是返回足够的识别信息,以便在任何后续请求中恢复用户帐户。具体来说,该done()方法的第二个参数是序列化到会话数据中的信息

您提供的反序列化函数旨在根据序列化到会话的标识信息返回用户配置文件

以下是Passport Guide中讨论会话部分的示例:

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

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

在上面的示例passport.serializeUser()中,提供了一个带有两个参数的函数,用户配置文件 ( user) 和回调函数 ( done)。回调函数将第二个参数作为从数据库中恢复帐户所需的标识信息(user.id但如果您使用的是 mongoDB,则可能是)。user._id这将在每个经过身份验证的请求上调用,并将标识信息存储在会话数据中(无论是在 cookie 中还是在您的 Redis 存储中)。

passport.deserializeUser()提供了一个函数,该函数也接受两个参数,标识信息 ( id) 和回调函数 ( done)。标识信息是在前一个请求中序列化为会话数据的内容 ( user.id)。这里的回调函数需要用户配置文件作为它的第二个参数,或者在检索配置文件作为它的第一个参数时引发的任何错误。该User.findById()函数是数据库中用户配置文件的查找函数。在此示例User中,对象是具有该findById()功能的猫鼬模型的实例。

提供的函数passport.deserializeUser()由护照中间件调用,passport.session()在路由处理之前将用户配置文件(user)存储到req.user

将 Redis 实现为会话存储

使用 Redis 的目的是在服务器端存储会话数据,因此客户端存储的唯一数据是会话 ID。同样,这与您实现护照的方式无关,只要您为应用程序添加了会话支持,护照就不会关心会话数据的存储位置。这个关于stackoverflow的previos question解决了如何实现Redis

于 2013-10-09T22:08:22.350 回答
30

有点晚了,但我已经理解了这个视觉上的东西

  1. 何时以及如何调用策略/本地/Facebook/etc 以及它如何到达 req.login 或 passport.serializeUser() 以及 done() 是什么?

passport.authenticate()调用您作为参数提供的相应策略,在那里您匹配req.body.passwordreq.body.username与存储的数据库或内存中存储的密码和用户名。如果用户发现您将其done()作为第二个参数传递给其他人return false

完成回调返回到passport.authenticate(). 如果 done 之前使用用户(即 done(null,user);)调用而不是req,logIn()自动调用或由用户在幕后调用

req.logIn()来电passport.serializeUser()

  1. 什么是 passport.serializeUser 以及调用此函数后 user.some_key 去哪儿了?

您在序列化函数中完成的第二个参数中提供的用户对象的键保存在会话中,并用于通过反序列化函数检索整个对象。

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

  1. 什么是 passport.deserializeUser 以及它在工作流程中的位置?

在反序列化函数中,您在反序列化函数的第一个参数中提供与序列化调用中的完成函数相同的用户对象键。所以你的整个对象都是在那个键的帮助下检索的。这里的键是 id(键可以是用户对象的任何键,即姓名、电子邮件等)在反序列化函数中,该键与内存数组/数据库或任何数据资源中的键匹配

获取的对象附加到请求对象为req.user

id键可以是用户对象的任何键,即name,email

视觉流

passport.authenticate()-----------
                                 |  
                                 |  invokes 
                                \./
       passport.use(new LocalStrategy(
            function(username, password, done) {

           // match req.body.username and req.body.password from any 
              //data base or in memory array
               if(user_is_found_and_pass_match)
                  done(null,user);--
               else                   | *1-user passed
                                      |
                  done(null,false);---| *2-user not passed
       });                            | 
                                      |return back to
passport.authenticate() <------------ |
                      |
                      |----- if user is passed in done() (*1) ,   
                            |
    req.login()   <--------- 
              |
 //authenticate() middleware  may  invoke req.login() automatically.
              |
              | calls
             \./  
 passport.serializeUser(function(user, done) {
        done(null, user.id); 
                     |
//use 'id'to serialize, you can use other or user object itself
    });              |-->saved to session req.session.passport.user = {id:'..'}
                     |
                     |__________________
                                       |          
    passport.deserializeUser(function(id, done) {
                      ________________|
                      | 
        User.findById(id, function(err, user) {
            done(err, user);
                       |______________>user object ataches to the request as req.user

     });
      });

这里id的键可以是用户对象的任何键,即name,email

于 2014-12-24T13:46:09.907 回答
13

给定以下配置express-sessionwithconnect-redis作为会话存储(使用 Express 4):

redis = require('redis').createClient(6379, '127.0.0.1');
session = require('express-session');
RedisStore = require('connect-redis')(session);

app.use(session({
  store: new RedisStore({
    client: redis
  }),
  secret: 's3cret',
  resave: true,
  saveUninitialized: true
}));

您可以只告诉护照序列化整个用户对象,而不仅仅是用户 ID。

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

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

整个用户对象将与 Redis 中的会话一起保存,并像req.user每个请求一样放置在请求上。

于 2014-10-26T04:43:42.803 回答