如何更新passportjs设置的req.user会话对象?

Posted

技术标签:

【中文标题】如何更新passportjs设置的req.user会话对象?【英文标题】:How to update req.user session object set by passportjs? 【发布时间】:2013-12-29 13:59:22 【问题描述】:

我已经尝试了很多天,但我所有的测试都失败了......

我平台上的用户通过使用 passportjs 策略(paypal、facebook、google...)连接他们。

当用户连接时,我将他的昵称写在标题的右侧。 header的html代码是从handlebars模板生成的,当这个部分由expressjs提供服务时,我将req.user会话对象发送到模板,以便写入昵称和其他信息......

顺便说一句,这很好用,但是当用户从他的个人资料更新他的昵称时我遇到了问题,我无法在服务器端更新会话对象,如果用户重新加载页面,旧昵称会再次出现。

而且我不想每次用户加载页面时都向数据库请求用户信息,所以我想保留这个配置:

// -- Passport session setup
passport.serializeUser(function(user, done)  done(null, user); );
passport.deserializeUser(function(obj, done)  done(null, obj); );

我设置本地的中间件:

// -- Set accessible datas from the template
res.locals = _.extend(res.locals, 
    user: req.user,
    query: req.url,
    title: app.config.title,
    url: app.config.url
);

我的失败:

// Trying to update req.user directly : not persistent
req.user.nickname = User.get('nickname');

// Trying to update passport session : exception error
req.session.passport.user = User.toJSON();

// Trying to replace full session object : not persistent
var session = req.session;
session.passport.user = User.toJSON();
req.session = session;

有什么建议吗?

目前,只有注销然后登录才有效...效率不高:)

编辑

// Application router
var Router = require('./helpers/router.js');

// Create Express Server
var app = express().http().io();

// -- Init app router
var router = new Router(app);

// -- Framework Middleware
app.use(router.middleware); 

#########################
/***
 * APP ROUTER
 **/

// Export router
module.exports = function(app) 

    // Set instance
    var router = this;

    // Returns routes register & middleware methods
    return 

        // -- Register routes
        register: function() 
            requirejs(['routes'], function(routes) 
                _.each(routes, function(name, route) 
                    app.get(route, function(req, res, next) 
                        requirejs(['views/'+name], function(view) 
                            if ( view ) 
                                var _view = new view(_.extend(req.params, server: req: req, res: res, next: next)); 
                                _view.render(name, req, res, next); 
                            
                            else 
                                next();
                            
                        , function (err) 
                            console.log('error' + err)

                        );
                    ); 
                );
            );
        ,

        // -- Bind middleware
        middleware: function(req, res, next) 

            // Get the current path
            console.log("Middleware :: "+req.url);

            // Add user informations
            res.locals = _.extend(res.locals, 
                user: req.user,
                query: req.url,
                title: app.config.title,
                url: app.config.url
            );

            // Go next 
            next(); 

        
    

【问题讨论】:

问题实际上是你在哪里分配 res.locals 和 req.user.nickname。你能显示更多的代码吗?这些行发生在什么功能中? 中间件在静态路由之后被调用,为视图设置本地变量并继续定义路由。我已经编辑了帖子以显示更多代码! Update logged in user details in session的可能重复 【参考方案1】:

这对我有效并持续存在:

req.session.passport.user.nickname = 'mynewnickname'

您是否在刷新前可能需要破坏的路线上使用缓存?

(护照序列化相同)

passport.serializeUser(function(user, done)  done(null, user); );
passport.deserializeUser(function(obj, done)  done(null, obj); );

【讨论】:

我确认,这也适用于我。感谢您的解决方法!【参考方案2】:

我也遇到了同样的问题,终于找到了解决办法:

var user = newDataObj;
req.logIn(user, function(error) 
    if (!error) 
       console.log('succcessfully updated user');
    
);
res.end(); // important to update session

req.logIn 将调用序列化函数并将新会话保存到数据库。 res.end() 很重要。没有它,会话将不会被保存。

【讨论】:

我想你的意思是用大写的 I 登录,而不是登录。【参考方案3】:

对于“serializeUser”,您将返回整个用户...这将序列化整个对象并将其放入用于跟踪会话的 cookie 中。该序列化只发生一次(建立会话时)。当下一个请求进来时,它总是反序列化您最初存储的完全相同的用户对象,它没有您对其进行的任何更新。这就是注销和重新登录有效的原因,因为它会从您的数据库中检索已编辑的用户(我假设),并重新创建会话跟踪 cookie。

要确认这个答案,请在“serializeUser”上放置一个断点,并注意它只有在您登录时才会被击中。

【讨论】:

【参考方案4】:

这仍然是“更新会话护照 js”的最佳结果之一,所以我想我会添加对我有用的内容(提供的答案对我不起作用):

req.session.passport.user.updatedfield= 'updatedvalue'
req.session.save(function(err) console.log(err);

如果没有req.session.save(),我的会话数据将不会更新。 希望这对某人有所帮助。

【讨论】:

【参考方案5】:

Quan Duong 的回答对我最有用,但这里有一个更现实的场景:

async function foo(req, res) 
  // get some data from somewhere
  const newNickname = req.body.nickname;

  // update the user database somehow - e.g. mongodb 
  const users = db.getCollection('users');
  await users.updateOne(
    _id: req.user._id
  , 
    $set: 
      nickname: newNickname
    
  );

  // create a temporary copy of the user w/ the updated property
  const updatedUser = req.user;
  updatedUser.nickname = newNickname

  // persist the change to the session
  req.login(updatedUser, async(error) => 
    if (error) 
      res.json(
        err: 'Sorry, there was an error updating your account.'
      );
      return;
    

    /* 
       maybe you need to call another function from here that uses the updated info before 
       responding to the original request
    */
    try 
      await bar(req.user);
     catch (error) 
      res.json(
        err: 'Sorry, there was an error updating your account.'
      );
      return;
    

    // done
    res.send(200);
  );

【讨论】:

以上是关于如何更新passportjs设置的req.user会话对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何告诉 Passport JS 中的 typescript req.user 永远不会被定义?

没有会话的 Passport js 身份验证

如何设置PassportJS进行后端身份验证?

express-jwt 将用户对象设置为 req.user._doc 而不仅仅是 req.user?

PassportJS - 自定义回调并将 Session 设置为 false

如何在 ApolloServer 中获取 req.user