我是否实现了序列化和反序列化NodesJS + Passport + RedisStore?

时间:2013-10-09 09:59:03

标签: node.js express redis passport.js

我是否实施了Serialize和Deserialize?

RedisStore设置为Express的会话存储。这是否意味着我不实现Serialize和Deserialize?它会自动发生吗?

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

以下代码似乎有效,但会话不会持续存在。我每次访问该网站时都需要登录。

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

3 个答案:

答案 0 :(得分:46)

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

使用护照实施会话

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

序列化功能的目的是返回足够的识别信息,以便在任何后续请求中恢复用户帐户。具体而言,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()函数的mongoose模型的实例。

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

将Redis实现为会话存储

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

的问题

答案 1 :(得分:25)

有点迟,但我已经让这个视觉事物理解了

  
      
  1. 何时以及如何调用策略/本地/ Facebook /等以及如何获取req.login或passport.serializeUser()以及什么是完成()?
  2.   

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

完成回调返回passport.authenticate()。如果先前使用用户调用完成(即done(null,user);),则会自动调用req,logIn()或在场景后面的用户调用

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

  
      
  1. 什么是passport.serializeUser以及在调用此函数后user.some_key在哪里?
  2.   

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

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

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

在反序列化函数中,您在反序列化函数的第一个参数中提供了在序列化调用中给予完成函数的用户对象的相同键。因此,您可以借助该密钥检索整个对象。这里的密钥是id(密钥可以是用户对象的任何密钥,即名称,电子邮件等) 在deSerialize函数中,该键与内存数组/数据库或任何数据资源

匹配

获取的对象作为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

答案 2 :(得分:11)

考虑到以express-session connect-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的形式放在请求上。