无法将多个用户保存到MongoDB

时间:2017-10-17 08:49:45

标签: javascript node.js mongodb mongoose passport.js

我正在使用nodeJS和expressJS服务器框架。这个问题是关于passportJS不能将超过1个用户保存到MongoDB。

首先,我设置了本地护照的电子邮件注册,并使其工作正常。其次,我设置了passport-facebook,这基本上打破了我的电子邮件注册。每个注册(电子邮件和Facebook)现在只登录一个用户,我必须继续从mongodb删除用户再次注册。当数据库中有1个用户并且我尝试注册另一个用户时 - 我收到以下错误。

process.nextTick(function() { throw err; });
                                  ^

TypeError: Cannot read property '1' of null    at model.mongodbErrorHandler (/Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose-mongodb-errors/lib/plugin.js:19:49)
at next (/Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/kareem/index.js:145:14)
at Kareem.execPost (/Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/kareem/index.js:193:3)
at /Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/lib/model.js:219:35
at /Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/lib/model.js:152:9
at /Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/mongodb/lib/collection.js:524:20
at /Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/mongodb/lib/collection.js:658:14
at handleCallback (/Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/mongodb/lib/utils.js:95:56)
at /Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/mongodb/lib/bulk/unordered.js:465:9
at handleCallback (/Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/mongodb/lib/utils.js:95:56)
at resultHandler (/Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/mongodb/lib/bulk/unordered.js:413:5)
at /Users/tlr/Dropbox/Websites/app-one/node_modules/mongoose/node_modules/mongodb-core/lib/connection/pool.js:455:18
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)

我认为问题可能在于用户架构,因为每个策略都会保存不同的用户信息。因此,本地& Facebook可能无法在数据库中正确结合导致错误?如果我错了,请纠正我。

要查看的主要文件是我的userSchema( User.js ),我的路径文件( index.js ),其中包含我的FB策略和模块导入,和我的控制器文件( userController.js,authController.js ),我导出我的模块和函数。

user.js的

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
const md5 = require('md5');
const validator = require('validator');
const mongodbErrorHandler = require('mongoose-mongodb-errors');
const passportLocalMongoose = require('passport-local-mongoose');

const userSchema = new Schema({
    name: {
        type: String,
        required: 'Please supply a name',
        trim: true,
    },

    email: {
        type: String,
        unique: true,
        lowercase: true,
        trim: true,
        required: 'Please supply an email address',
        validate: [validator.isEmail, 'Invalid Email Address']
    },
    id: String,
    token: String
});

userSchema.plugin(passportLocalMongoose, { usernameField: 'email' });
userSchema.plugin(mongodbErrorHandler);

module.exports = mongoose.model('User', userSchema);

index.js

const express = require('express');
const mongoose = require('mongoose');
const passport = require('passport');
const User = mongoose.model('User');
const authIDs = require('../../oauth');
const authController = require('../controllers/authController');
const userController = require('../controllers/userController');
const FacebookStrategy = require('passport-facebook').Strategy;
const router = express.Router();

passport.use(new FacebookStrategy({
        clientID: authIDs.facebook.clientID,
        clientSecret: authIDs.facebook.clientSecret,
        callbackURL: authIDs.facebook.callbackURL,
        profileFields: ['id', 'emails', 'name'],
        passReqToCallback : true
    },

    function(req, accessToken, refreshToken, profile, done) {
        const newUser = new User();
        newUser.id = profile.id;
        newUser.token = accessToken;
        newUser.name = profile.name.givenName;
        newUser.email = profile.emails[0].value;

        process.nextTick( function() {
            User.findOne({id: profile.id}, (err, user) => {
                if (err) {
                    return done(err);
                }
                if (!user) {
                    newUser.save().then( user => {
                        done( null, user );
                    } ).catch( err => {
                        done( err );
                    } );
                } else {
                    return done(null, user);
                }
            });
        });
    }
));

router.get( '/login', userController.loginForm);
router.post( '/login', authController.login);
router.get( '/register', userController.registerForm);
router.post( '/register',
    userController.validateRegister,
    userController.register,
    authController.login
);

router.get('/auth/facebook', authController.fbauth);
router.get('/auth/facebook/callback', authController.fbcallback);

router.get( '/logout', authController.logout);

router.get('/', (req, res) => {
    res.render('home');
});

module.exports = router;

userController.js

const mongoose = require('mongoose');
const User = mongoose.model('User');
const promisify = require('es6-promisify');

exports.loginForm = (req, res) => {
    res.render('login')
};

exports.registerForm = (req, res) => {
    res.render('register')
};

exports.validateRegister = (req, res, next) => {
    // express validator methods below
    req.sanitizeBody('name');
    req.checkBody('name', 'You must supply a name!').notEmpty();
    req.checkBody('email', 'That email is not valid!').isEmail();
    req.sanitizeBody('email').normalizeEmail({
        remove_dots: false,
        remove_extension: false,
        gmail_remove_subaddress: false
    });
    req.checkBody('password', 'Password cannot be blank!').notEmpty();
    req.checkBody('password-confirm', 'Confirmed password cannot be blank!').notEmpty();
    req.checkBody('password-confirm', 'Oops! Your passwords do not match').equals(req.body.password);

    const errors = req.validationErrors();

    if (errors) {
        req.flash('error', errors.map(err => err.msg));
        res.render('register', { body: req.body, flashes: req.flash() });
        return;
    }
    next();
};

exports.register = async (req, res, next) => {
    const user = new User({ name: req.body.name, email: req.body.email});
    const register = promisify(User.register, User);
    await register(user, req.body.password);
    next();
};

authController.js

const passport = require('passport');
const mongoose = require('mongoose');
const User = mongoose.model('User');

exports.login = passport.authenticate('local', {
    failureRedirect: '/login',
    failureFlash: 'Failed Login!',
    successRedirect: '/',
    successFlash: 'You are now logged in!'
});

exports.fbauth = passport.authenticate('facebook', {scope: ['email']});

exports.fbcallback = passport.authenticate('facebook', {
        failureRedirect: '/login',
        failureFlash: 'Failed Login!',
        successRedirect: '/',
        successFlash: 'You are now logged in!'
});

exports.logout = (req, res, next) => {
    req.logout();
    req.flash('success', 'You successfully logged out!');
    res.redirect('/login')
};

任何有关修复的建议都将受到高度赞赏的suuuuuuuuuper duuuuuuper。

1 个答案:

答案 0 :(得分:0)

经过几个小时的尝试后,我的上帝就像大多数编码中遇到的问题一样,这个问题非常令人尴尬。

因为我使用上述问题中提到的代码,您可以看到我实施了本地电子邮件注册以及passport-facebook身份验证。所以...导致这个令人困惑的错误的原因是以下代码是这样的:

passport.serializeUser(User.serializeUser(), function(user, done) {
    done(null, user.id);
});

passport.deserializeUser(User.deserializeUser(), function(id, done) {
    User.findById(id, function(err, user) {
        done(err, user);
    });
});

而不是简单地这样:

passport.serializeUser(User.serializeUser(), function(user, done) {
    done(null, user);
});

passport.deserializeUser(User.deserializeUser(), function(user, done) {
    done(null, user);
});