Question

I'm building a simple site with expressjs and passportjs and I'm running into the problem that I can't access session variables in my routes.

There are a lot of threads with this topic but the solutions don't work for me. It looks like my error is somewhere else.

My app is configured like this:

app.configure(function() {
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.logger());
    app.use(express.cookieParser());
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.session({
        path: '/',
        secret: 'very secret'
    }));

    app.use(passport.initialize());
    app.use(passport.session());
    app.use(app.router);
    app.use(express.static(__dirname + '/public'));
});

Once passport verified the twitter account it's redirected to this site:

app.get('/auth/twitter/callback',
    passport.authenticate('twitter', {
        failureRedirect: '/login'
    }),
    function(req, res) {
        res.redirect('/');
        console.log("populate session")
        populateSession(req, res);
    });

This works, as I'm seeing the "populate session" output in the console if I'm logged in.

The populateSession() looks like this:

function populateSession(req, res) {
    User.findOne({
        twitterID: req.user.id
    }, function(err, result) {
        if (result) {
            // Store data to session
            req.session.twitterAccessToken = result.twitterAccessToken;
            req.session.twitterAccessTokenSecret = result.twitterAccessTokenSecret;
            req.session.lastfmAccountName = result.lastfmAccountName;

            console.log("in session: " + req.session.lastfmAccountName)
        }
    })
}

"in session" is printed the right way. So the session itself works. Now my problem is that I want to have access to my session variables in routes because I want to pass them to my view templates like this:

app.get('/account', ensureAuthenticated, function(req, res) {
    console.log(req.session)
    console.log("lastfm nick " + req.session.lastfmAccountName)
    res.render('account', {
        user: req.user,
        lastfmnick: req.session.lastfmAccountName
    });

That's where I'm running into the problems. req.session contains all the twitter fields passport is populating it with but req.session.lastfmAccountName is undefined.

Any idea what's wrong there or is there a better way to pass variables to the view? I feel like it's not a good idea to have DB queries for the fields in all my routes if it could just be stored in the session.

Thanks!

Était-ce utile?

La solution

The session will automatically be saved when the response ends, in this case by res.redirect(), which is done before the modifications are made to the session.

function(req, res) {
    res.redirect('/');         // ends the response, saving the session

    populateSession(req, res); // modifies the session without saving
});

Since .findOne() is asynchronous, if you revise populateSession() to take and call a callback when the find completes, you can control the order so the session is modified first:

function populateSession(req, res, next) {
    User.findOne({
        twitterID: req.user.id
    }, function(err, result) {
        if (result) {
            // ...
        }

        if (next) next(err);
    })
}
app.get('/auth/twitter/callback',
    /* ... */,
    function(req, res) {
        populateSession(req, res, function () {
            res.redirect('/');
        });
    });

It also allows you to use populateSession as middleware:

app.get('/auth/twitter/callback',
    /* ... */,
    populateSession,
    function(req, res) {
        res.redirect('/');
    });

Autres conseils

 app.use(lib.express.cookieParser(lib.config.cookieSecret));
 app.use(lib.express.session({
secret: 'very secret'
 })
 }));

This two line should be consecutive and in that order.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top