【问题标题】:correct way to use passport local with passport facebook/google使用本地护照和护照 facebook/google 的正确方法
【发布时间】:2019-05-23 07:10:37
【问题描述】:

所以我一直在思考这个问题。

对于那些不想使用 facebook/google 注册的用户,我使用本地护照,而对于喜欢使用社交登录快速注册的用户,我使用的是 passport-google 和 facebook。

由于这是我的第一个应用程序,我无法理解如何我可以同时使用这两个应用程序。

例如,我正在创建一个模式来存储用户数据

const mongoose = require('mongoose')
const userSchema = new mongoose.Schema({
    fullName: String,
    email: String,
    passowrd: String, 
    image: String
}) 


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

架构有密码字段。现在,社交登录不会发送用户密码,但对于本地登录,我们需要使用密码。

我能想到的唯一选择是创建两个模式,一个带密码,一个不带密码。

问题:人们通常会这样做吗?喜欢这是最好的方法,或者有人可以建议我一个更好的替代方法

【问题讨论】:

  • @SaurabhMistry 非常感谢您的回答,我仍然要检查您的代码。我会在晚上阅读并尝试一次(尽管赞成)

标签: node.js express mongoose passport.js


【解决方案1】:

你的User schema应该是:

const mongoose = require('mongoose')
var Schema=mongoose.Schema;
var bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
    fullName: {type:String,required:true,default:''},
    email: {type:String,required:true,unique:true},
    email_verified:{type:Boolean,default:false},
    verify_token:{type:String,default:null},
    provider:{type:String,default:'email'},
    provider_id:{type:String,default:null},
    password: {type:String}, 
    password_reset_token:{type:String,default:null},
    image: {type:String,default:null},
    created_at:{type:Date,default:Date.now},
    updated_at:{type:Date,default:Date.now},
},{
    collection:'User'
 }); 

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

 module.exports.encryptPassword=function(password)
{
 var salt= bcrypt.genSaltSync(10);
 var hash=  bcrypt.hashSync(password,salt,null);    
 return hash;
}


module.exports.validPassword=function(password,hash){
 return bcrypt.compareSync(password,hash);  
}

这里添加了一些额外的有用字段:

  • email_verified:用于检查用户是否已验证电子邮件

  • provider :注册提供者,如 facebook 、 google..etc ...默认 如果用户使用电子邮件注册,则为电子邮件。

  • provider_id:提供者 id 是社交提供的用户的唯一 id 媒体(Facebook、谷歌)

  • password_reset_token:是随机令牌字符串,当用户忘记密码并通过电子邮件发送此令牌以重置密码时

  • 现在,当用户使用电子邮件注册时,保存用户输入的密码。

  • 当用户使用社交媒体提供商(facebook、google)注册时..然后生成随机字符串,使用 bcrypt 创建密码 并保存到密码字段,记住:使用社交媒体注册的用户的密码字段不能为空。

现在创建文件passport.js

var FacebookStrategy = require('passport-facebook').Strategy;
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;

var User       = require('../models/user');


module.exports = function(passport) {

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

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


  passport.use(new FacebookStrategy({

    clientID        : 'clientID',
    clientSecret    : 'clientSecret',
    callbackURL     : 'callbackURL'

},
// facebook will send back the token and profile
function(token, refreshToken, profile, done) {
    console.log("TOKEN = "+token);
    console.log("REFRESH TOKEN = "+refreshToken);
    console.log("PROFILE = "+JSON.stringify(profile));

        // find the user in the database based on their facebook id
        User.findOne({ 'provider_id' : profile.id }, function(err, user) {

            if (err)
                return done(err);

            if (user) {
                return done(null, user); // user found, return that user
            } else {
                console.log(profile);
                let randomString= Math.random().toString(36).substring(2);
                var newUser = new User({
                  fullName  : profile.displayName,
                  email :profile.emails[0].value, 
                  email_verified : true,
                  password : User.encryptPassword(randomString),
                  image : 'get user image from response',
                  provider : 'facebook',
                  provider_id : profile.id,    
                });

               newUser.save(function(err) {
                    if (err)
                        throw err;
                    return done(null, newUser);
                });
           }

        });

}));



  passport.use(new GoogleStrategy({
    clientID        : 'clientID',
    clientSecret    : 'clientSecret',
    callbackURL     : 'callbackURL',
  },
function(token, refreshToken, profile, done) {

         User.findOne({ 'provider_id' : profile.id }, function(err, user) {
            if (err)
                return done(err);
            if (user) {
          return done(null, user);
            } else {
                let randomString= Math.random().toString(36).substring(2);
                var newUser = new User({
                  fullName  : profile.displayName,
                  email :profile.emails[0].value, 
                  email_verified : true,
                  password : User.encryptPassword(randomString),
                  image : 'get user image from response',
                  provider : 'google',
                  provider_id : profile.id,    
                });
                newUser.save(function(err) {
                    if (err)
                        throw err;
                    return done(null, newUser);
                });
            }
        });
}));


}

额外的注意事项:当用户使用 facebook/google 注册时,设置email_verified:true,因为用户已经通过提供商验证了他的电子邮件,

当用户使用他的电子邮件集email_verified:false注册并生成随机令牌并在创建用户时设置verify_token:'random token',然后使用带有此随机令牌的NodeMailer发送帐户验证电子邮件,验证链接

生成处理邮件验证的新路由,如/verify,当用户从邮件中点击链接时,该路由将处理请求,通过verify_token查找用户并设置email_verified : true,如果令牌正确则显示错误。

希望我的回答能帮到你:)

【讨论】:

    猜你喜欢
    • 2017-10-13
    • 1970-01-01
    • 2019-01-06
    • 2016-08-14
    • 1970-01-01
    • 2019-06-23
    • 1970-01-01
    • 2017-08-18
    • 2014-09-02
    相关资源
    最近更新 更多