Express cookieSession和Mongoose:我如何使request.session.user成为一个Mongoose模型? [英] Express cookieSession and Mongoose: how can I make request.session.user be a Mongoose model?

查看:111
本文介绍了Express cookieSession和Mongoose:我如何使request.session.user成为一个Mongoose模型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当创建新的用户帐户时,我创建newUser,一个Mongoose模型实例,如下所示:

  _events:Object 
错误:undefined
isNew:false
save:function(){
参数:null
调用者:null
_doc:Object
名称:'Joe Smith'
...

对象的实际数据在 _doc 属性,虽然存在getter和setter,但您可以运行:

  user.name ='Jane Doe'

,这样可以正常运行。我运行:

  request.session.user = newUser; 

将用户保存到会话中。到目前为止,这么好。



然而,在随后的请求中,request.session.user似乎只是_doc中的东西。例如:

  name:'Joe Smith'

这是很好的,但这意味着我无法运行例如 request.session.user.save()来保存更改。



我可以简单地让一些中间件查找与数据相关联的用户。但是我想知道更多关于Express和Mongoose在这里的工作。



如何让request.session.user成为一个Mongoose模型?



更新:我当前的中间件黑客:

  /用作需要用户的路由的中间件
// TODO:只需要由于request.session.user被保存奇怪的
var rehydrateUser = function(request,response,next){
if(request.session.user){
var hydrated = request.session.user.save
if(!hydrated){
console.log('Rehydrating user ...');
models.User.findOne({somefield:request.session.user.somefield},function(err,user){
if(err){
request.session.error ='User没有找到DB!';
request.redirect('/');
} else {
request.session.user = user;
console.log('Rehydrated user !);
next();
}
})
} else {
next();
}
} else {
console.log('session中没有用户')
next();
}
}


解决方案

Express会话被存储为单独的存储,并且对那里可以存储的内容有限制。它不能存储原型数据(方法)。看看它更像是 key<> value 存储。



这个原因是该会话可以存储在任何地方(几乎),如:进程内存;数据库(mongodb); Redis的;因为这样,一旦你把任何东西放在会话对象中,并且请求完成,express将会占用会话数据,解析它并粘贴到会话存储中,就像纯对象一样。默认情况下是进程内存,但是如前所述 - 可以是任何其他存储。



所以当下一个http请求发生时,会话中间件将尝试使用cookie恢复会话如果使用)请求头中的数据,并将要求会话存储提供数据。由于它已经被格式化 - 它不会有.prototype的东西,只是数据(对象数组 string number 和其他简单的东西)。



所以你需要再次创建Model的数据。

您可以通过express中的中间件来执行。所以在 app.configure 中定义 session 后,可以执行以下操作:

  app.use(function(req,res,next){
if(req.session&& req.session.user){
req.session.user = new UserModel(req.session.user);
}
return next();
});

这将检查是否定义会话以及用户。然后将从该数据中重新创建猫头鹰模型。



如在评论中提到的那样 - 您不应该在会话中存储用户数据,因为会导致不一致由于数据所有权分担责任。
所以只存储用户的 ID ,然后使用中间件从数据库加载。

  app.use(function(req,res,next){
if(req.session&& req.session.userID){
UserModel.findById(req。 session.userID,function(err,user){
if(!err&& user){
req.user = user;
next();
} else {
next(new Error('Could not restore User from Session。'));
}
});
} else {
next();
}
});

您可以创建中间件来检查用户是否登录:

  function userRequired(req,res,next){
if(req.user){
next();
} else {
next(new Error('Not Logged In');
}
}

使用它:

  app.get('/ items' ,userRequired,function(req,res,next){
//只有在用户登录时才会到达(req.user!== undefined)
});


When a new user account is created, I create newUser, a Mongoose model instance that looks like:

_events: Object
errors: undefined
isNew: false
save: function () {
arguments: null
caller: null
_doc: Object
  name: 'Joe Smith'
...

The actual data for the object is in the _doc property, though getters and setters exist so you can run:

user.name = 'Jane Doe' 

and that will work fine. I run:

request.session.user = newUser;

To save the user to the session. So far, so good.

However, in subsequent requests, request.session.user seems to be only the stuff in _doc. Eg:

name: 'Joe Smith'

Which is nice, but that means I can't run eg, request.session.user.save() to save changes.

I could simply make some middleware to look up the user associated with the data. But I'd like to know more about what Express and Mongoose are doing here.

How can I make request.session.user be a Mongoose model?

Update: my current middleware hack:

// Use as a middleware on routes which need users
// TODO: only needed due to request.session.user being saved weirdly
var rehydrateUser = function(request, response, next) {
  if ( request.session.user ) {
    var hydrated = request.session.user.save
    if ( ! hydrated ) {
      console.log('Rehydrating user...');
      models.User.findOne({ somefield: request.session.user.somefield }, function (err, user) {
        if ( err ) {
          request.session.error = 'User not found in DB!';
          request.redirect('/');
        } else {
          request.session.user = user;          
          console.log('Rehydrated user! All repos already being monitored.');
          next();
        }
      })
    } else {
      next();
    }
  } else {
    console.log('No user in session')
    next();
  }
}

解决方案

Express session is stored as separate storage and has limitations to what can be stored there. It cannot store prototype data (methods). Look at it more like key<>value storage.

Reasons for this is that session can be stored anywhere (pretty much), such as: process memory; databases (mongodb); redis; etc.

Because of this, once you put anything in session object and request is finished, express will take session data, parse it and stick into session store just as pure object. By default it is process memory, but as mentioned before - can be any other storages.

So when next http request happens, session middleware will try to restore session using cookie (if it is used) data in request headers, and will ask session storage to provide data back. As it is already formatted - it will not have .prototype stuff but just data (object, array, string, number, and other simple stuff).

So you need to create Model out of that data again.
You can do by middleware in express. So in app.configure straight after defining session you can do this:

app.use(function(req, res, next) {
  if (req.session && req.session.user) {
    req.session.user = new UserModel(req.session.user);
  }
  return next();
});

This will check if session is defined as well as user. And then will recreate mongoose model out of that data.

As mentioned here in comments - you should not store user data in session as it will lead to inconsistencies due to split of responsibilities over ownership of data. So store just ID of user, and then using middleware load it from Database.

app.use(function(req, res, next) {
  if (req.session && req.session.userID) {
    UserModel.findById(req.session.userID, function(err, user) {
      if (!err && user) {
        req.user = user;
        next();
      } else {
        next(new Error('Could not restore User from Session.'));
      }
    });
  } else {
    next();
  }
});

After you can create middleware to check if user is logged in:

function userRequired(req, res, next) {
  if (req.user) {
    next();
  } else {
    next(new Error('Not Logged In');
  }
}

And use it like that:

app.get('/items', userRequired, function(req, res, next) {
  // will only come here if user is logged in (req.user !== undefined)
});

这篇关于Express cookieSession和Mongoose:我如何使request.session.user成为一个Mongoose模型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆