使用Node.js进行Facebook Passport身份验证无法在Production(Heroku)中使用

时间:2015-10-17 00:14:43

标签: node.js facebook heroku oauth passport.js

一切都在localhost中运行。在生产中(使用Heroku),我设置了Facebook ID和Secret,但没有收到任何重定向错误。但是,当我尝试进行身份验证时,该网址会更改为https://xxxx.herokuapp.com/xxxx.herokuapp.com/auth/facebook/callback?code=yyyyyy,然后重定向回登录页面而不会将用户登录。

可能导致此问题的任何想法?

Facebook Index.js

    var express = require('express');
    var passport = require('passport');
    var auth = require('../auth.service');

    var router = express.Router();

    router
      .get('/', passport.authenticate('facebook', {
        scope: ['email', 'user_about_me'],
        failureRedirect: '/signup',
        session: false
      }))

      .get('/callback', auth.addAuthHeaderFromCookie(), passport.authenticate('facebook', {
        failureRedirect: '/signup',
        session: false
      }), auth.setTokenCookie)
      ;

    module.exports = router;

passport.js

exports.setup = function (User, config) {
  passport.use(new FacebookStrategy({
      clientID: config.facebook.clientID,
      clientSecret: config.facebook.clientSecret,
      callbackURL: config.facebook.callbackURL,
      profileFields: [
      'displayName',
      'emails',
      'gender'
      ]
    },
    function(accessToken, refreshToken, profile, done) {
      console.log(profile)
      User.findOne({
        'facebook.id': profile.id
      },
      function(err, user) {
        if (err) {
          return done(err);
        }
        if (!user) {
          user = new User({
            name: profile.displayName,
            firstName: profile.displayName.substr(0, profile.displayName.indexOf(" ")),
            nickname: profile.displayName.substr(0, profile.displayName.indexOf(" ")),
            lastName: profile.displayName.split(' ').pop(),
            gender: profile.gender,
            email: profile.emails[0].value,
            role: 'user',
            username: profile.username,
            provider: 'facebook',
            facebook: profile._json
          });
          user.save(function(err) {
            if (err) return done(err);
            done(err, user);
          });
        } else {
          return done(err, user);
        }
      })
    }
  ));
};

auth.service.js

var mongoose = require('mongoose');
var passport = require('passport');
var config = require('../config/environment');
var jwt = require('jsonwebtoken');
var expressJwt = require('express-jwt');
var compose = require('composable-middleware');
var User = require('../api/user/user.model');
var validateJwt = expressJwt({ secret: config.secrets.session });

/**
 * Attaches the user object to the request if authenticated
 * Otherwise returns 403
 */
function isAuthenticated() {
  return compose()
    // Validate jwt
    .use(function(req, res, next) {
      // allow access_token to be passed through query parameter as well
      if(req.query && req.query.hasOwnProperty('access_token')) {
        req.headers.authorization = 'Bearer ' + req.query.access_token;
      }
      validateJwt(req, res, next);
    })
    // Attach user to request
    .use(function(req, res, next) {
      User.findById(req.user._id, function (err, user) {
        if (err) return next(err);
        if (!user) return res.status(401).send('Unauthorized');

        req.user = user;
        next();
      });
    });
}

/**
 * Checks if the user role meets the minimum requirements of the route
 */
function hasRole(roleRequired) {
  if (!roleRequired) throw new Error('Required role needs to be set');

  return compose()
    .use(isAuthenticated())
    .use(function meetsRequirements(req, res, next) {
      if (config.userRoles.indexOf(req.user.role) >= config.userRoles.indexOf(roleRequired)) {
        next();
      }
      else {
        res.status(403).send('Forbidden');
      }
    });
}

/**
 * If there is a user, appends it to the req
 * else req.user would be undefined
 */
function appendUser() {
    return compose()
        // Attach user to request
        .use(function(req, res, next) {
            validateJwt(req, res, function(val) {
                if(_.isUndefined(val)) {
                    User.findById(req.user._id, function(err, user) {
                        if(err) {
                            return next(err);
                        } else if(!user) {
                            req.user = undefined;
                            return next();
                        } else {
                            req.user = user;
                            next();
                        }
                    });
                } else {
                    req.user = undefined;
                    next();
                }
            });
        });
}

/**
 * Takes the token cookie and adds the header
 * for it on the request
 */
function addAuthHeaderFromCookie() {
    return compose()
        .use(function(req, res, next) {
            if(req.cookies.token) {
                req.headers.authorization = 'Bearer ' + _.trim(req.cookies.token, '\"');
            }
            return next();
        });
}

/**
 * Returns a jwt token signed by the app secret
 */
function signToken(id, role) {
  return jwt.sign({ _id: id, role: role }, config.secrets.session, { expiresIn: "5h" });
}

/**
 * Set token cookie directly for oAuth strategies
 */
function setTokenCookie(req, res) {
  console.log("setting Token Cookie");
  if (!req.user) return res.status(404).json({ message: 'Something went wrong, please try again.'});
  console.log(req.user);
  var token = signToken(req.user._id, req.user.role);
  res.cookie('token', JSON.stringify(token));
  res.redirect('/');
}

exports.isAuthenticated = isAuthenticated;
exports.hasRole = hasRole;
exports.signToken = signToken;
exports.setTokenCookie = setTokenCookie;
exports.addAuthHeaderFromCookie = addAuthHeaderFromCookie;
exports.appendUser = appendUser;

config index.js

var path = require('path');
var _ = require('lodash');

function requiredProcessEnv(name) {
  if(!process.env[name]) {
    throw new Error('You must set the ' + name + ' environment variable');
  }
  return process.env[name];
}

// All configurations will extend these options
// ============================================
var all = {
  env: process.env.NODE_ENV,

  // Root path of server
  root: path.normalize(__dirname + '/../../..'),

  // Server port
  port: process.env.PORT || 9000,

  // Server IP
  ip: process.env.IP || '0.0.0.0',

  // Should we populate the DB with sample data?
  seedDB: false,

  // Secret for session, you will want to change this and make it an environment variable
  secrets: {
    session: process.env.Session_Secret || "xxxx"
  },

  // List of user roles
  userRoles: ['guest', 'user', 'admin'],

  // MongoDB connection options
  mongo: {
    options: {
      db: {
        safe: true
      }
    }
  },

  facebook: {
    clientID:     process.env.FACEBOOK_ID || 'id',
    clientSecret: process.env.FACEBOOK_SECRET || 'secret',
    callbackURL:  (process.env.DOMAIN || '') + '/auth/facebook/callback'
  },

  twitter: {
    clientID:     process.env.TWITTER_ID || 'id',
    clientSecret: process.env.TWITTER_SECRET || 'secret',
    callbackURL:  (process.env.DOMAIN || '') + '/auth/twitter/callback'
  },

  google: {
    clientID:     process.env.GOOGLE_ID || 'id',
    clientSecret: process.env.GOOGLE_SECRET || 'secret',
    callbackURL:  (process.env.DOMAIN || '') + '/auth/google/callback'
  }
};

// Export the config object based on the NODE_ENV
// ==============================================
module.exports = _.merge(
  all,
  require('./' + process.env.NODE_ENV + '.js') || {});

auth index.js

    var express = require('express');
    var passport = require('passport');
    var config = require('../config/environment');
    var User = require('../api/user/user.model');

    // Passport Configuration
    require('./local/passport').setup(User, config);
    require('./facebook/passport').setup(User, config);
    require('./google/passport').setup(User, config);
    require('./twitter/passport').setup(User, config);

    var router = express.Router();

    router.use('/local', require('./local'));
    router.use('/facebook', require('./facebook'));
    router.use('/twitter', require('./twitter'));
    router.use('/google', require('./google'));

    module.exports = router;

0 个答案:

没有答案