Pass user info in routes from Passport strategies

2020-07-16 12:11发布

问题:

I am trying to authenticate user using passportjs using express.

Passport.js looks like this.

var USER_INFO = {};
var FB_CALLBACK = 'http://localhost:3000/auth/facebook/callback';
module.exports = function(passport) {
	passport.use(new FacebookStrategy({
		clientID: FB_CLIENT_ID,
		clientSecret: FB_CLIENT_SECRET,
		callbackURL: FB_CALLBACK
	}, 
	function(accessToken, refreshToken, profile, done) {
		process.nextTick(function() {
			USER_INFO.id = profile.id;
		});
	}));
}

var express = require('express'); // call express
var app = express(); // define our app using express
var router = express.Router(); // get an instance of the express Route
var passport = require('passport');
USER_INFO = {};
require('./config/passport')(passport);
app.get('/auth/facebook', passport.authenticate('facebook'));

app.get('/auth/facebook/callback', passport.authenticate('facebook', {
    successRedirect : '/fb',
    failureRedirect : '/error'
}));

app.get('/fb', function (req, res) {
    res.json(USER_INFO);
}); 

I want all the information extracted in res.json(user_info). But it is coming as empty. What I am missing here. What is the best method to save user basic info of user to keep him logged in.

回答1:

Firstly, you should not store USER_INFO = {} outside the scope of your current request. If two separate users make a request then they'll get the same object.

You should at least store them in a way you can retrieve them separately

var USERS = {};
...
module.exports...
passport.use...
...

function(accessToken, refreshToken, profile, done) {
    USERS[profile.id] = profile;
    done(null, profile);
}));

Now if two separate users make a request they'll have their info separately stored within USERS

{
    1234: {id: 1234, name: FOO},
    6789: {id: 6789, name: BAR},
}

And done(null, profile) would serialize that user. If you haven't defined your serialize/deserialize functions you should do so like this:

passport.serializeUser(function (user, done) {
    done(null, user.id);
});
passport.deserializeUser(function (id, done) {
    var user = USERS[id];
    done(null, user);
});

Now your users will be available within their respective request contexts as req.user

So you just need to do:

app.get('/fb', function (req, res) {
    res.json(req.user);
}); 


回答2:

You forgot call done() in process.nextTick().

var FB_CALLBACK = 'http://localhost:3000/auth/facebook/callback';
module.exports = function(passport) {
    passport.use(new FacebookStrategy({
        clientID: FB_CLIENT_ID,
        clientSecret: FB_CLIENT_SECRET,
        callbackURL: FB_CALLBACK
    }, 
    function(accessToken, refreshToken, profile, done) {
        process.nextTick(function() {
            var USER_INFO = {};
            USER_INFO.id = profile.id;
            done(USER_INFO)
        });
    }));
}

You can pass any object to done(), it will become req.user later in your route. In your case, the USER_INFO which you want to response is req.user

app.get('/fb', function (req, res) {
    res.json(req.user);
});