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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19268812/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:54:46  来源:igfitidea点击:

Do I implement serialize and deserialize NodesJS + Passport + RedisStore?

node.jsexpressredispassport.js

提问by wisemanIV

Do I implement Serialize and Deserialize?

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

RedisStore is setup as my session store with Express. Does this mean that I DO NOT implement Serialize and Deserialize? Will it happen automatically?

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

When I don't implement these methods I get the following Express error - 500 Error: failed to serialize user into session. When I do implement them I'm not sure what to put in the Deserialize.

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

The code below appears to work but the sessions are not persisting. I need to login everytime I visit the site.

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

Is there a good example anywhere of NodeJS + Passport + RedisStore?

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

回答by Weston

If you are using sessionsyou have to provide passport with a serialize and deserialize function. Implementing Redis as a session store has nothing to do with how passport was implement, it only deals with where the session data is stored.

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

Implementing Sessions with passport

使用护照实施会话

As I said, the serialize and deserialize functions must be provided to passport for sessions to work.

正如我所说,序列化和反序列化功能必须提供给通行证才能工作。

The purpose of the serializefunction is to return sufficient identifying information to recover the user account on any subsequent requests. Specifically the the second parameter of the done()method is the information serialized into the session data.

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

The deserializefunction that you provide is intended to return the user profile based on the identifying information that was serialized to the session.

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

Here is the example from the Passport Guidein the section discussing sessions:

以下是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);
  });
});

In the above example passport.serializeUser()is provided a function that takes two parameters, the user profile (user) and a callback function (done). The callback function takes as it's second parameter the identifying information (user.id, but if you're using mongoDB this may be user._id) required to recover the account from the database. This will be called on every authenticated request and stores the identifying information in the session data (whether that is in a cookie or your Redis store).

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

passport.deserializeUser()is provided a function that also takes two parameters, the identifying information (id) and again a callback function (done). The identifying information is what was serialized to the session data in the previous request (user.id). The callback function here requires the user profile as it's second parameter, or any error in raised in retrieving the profile as it's first parameter. The User.findById()function is a lookup function for the user profile in the database. In this example Userobject is an instance of a mongoose model which has the findById()function.

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

The function provided to passport.deserializeUser()is called by the passport middleware, passport.session()prior to the route handling to store the user profile (user) to req.user.

在将用户配置文件 ( )存储到 的路由处理之前,passport.deserializeUser()通行证中间件会调用提供给 的函数。passport.session()userreq.user

Implementing Redis as a Session Store

将 Redis 实现为会话存储

The purpose of using Redis is to store session data server side so the only data stored client side is the session id. Again, this is independant of how you have implemented passport, passport doesn't care where the session data is being stored as long as you have added session support to your app. This previos question on stackoverflowaddresses how to implement Redis

使用Redis的目的是在服务器端存储会话数据,因此客户端存储的唯一数据是会话ID。同样,这与您如何实施通行证无关,通行证并不关心会话数据的存储位置,只要您向应用程序添加了会话支持。这个关于 stackoverflow 的上一个问题解决了如何实现 Redis

回答by A.B

Bit late but i have made this visual thing to understand

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

  1. When and how is is an strategy/local/Facebook/etc called and how it gets to req.login or passport.serializeUser() and whats with done()?
  1. 何时以及如何调用策略/本地/Facebook/etc 以及它如何到达 req.login 或passport.serializeUser() 以及done() 是什么?

passport.authenticate()invokes the respective strategy you provide as an argument, there you match req.body.passwordand req.body.usernamewith the database stored or in memory stored password and username. if user found you pass it to done()as second argument else you return false

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

The done callback return back to passport.authenticate(). if done is called previously with user (ie done(null,user);) than req,logIn()is called automatically or by user behind the scene

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

req.logIn()calls passport.serializeUser()

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

  1. Whats passport.serializeUser and Where does user.some_key go after this function has been called?
  1. 什么是passport.serializeUser 和user.some_key 在这个函数被调用后去哪里?

the key of user object you provide in second argument of the done in serialize function is saved in session and is used to retrieve the whole object via deserialize function.

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

Serialize function determine what data from the user object should be stored in the session. The result of the serializeUser method is attached to the session as req.session.passport.user = {}here for instance it would be(as we provide id as key) req.session.passport.user = {id:'xyz'}

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

  1. What is passport.deserializeUser and where does it fit in the workflow?
  1. 什么是passport.deserializeUser 以及它在工作流程中的位置?

In deserialize function you provide in first argument of deserialize function that same key of user object that was given to done function in serialize call. so your whole object is retrieved with help of that key. that key here is id(key can be any key of the user object ie name,email etc) In deSerialize function that key is matched with in memory array / database or any data resource

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

The fetched object is attached to request object as req.user

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

idkey can be any key of the user object ie name,emailetc

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

Visual Flow

视觉流

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

     });
      });

here idkey can be any key of the user object ie name,emailetc

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

回答by Andrew Homeyer

Given the following configuration of express-sessionwith connect-redisas the session store (using Express 4):

给定以下配置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
}));

You can just tell passport to serialize the entire user object, instead of just the user id.

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

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

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

The entire user object will be saved with the session in Redis, and placed on the request as req.userfor every request.

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