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)
});
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加