护照:允许注册姓名和电子邮件地址? (本地战略)

时间:2015-09-04 12:29:55

标签: javascript node.js passport.js passport-local

有没有办法允许用户使用他的密码,电子邮件和姓名注册本地策略?
我在网上找到的每个例子都只使用名称/密码或电子邮件/密码。

我还搜索了整个护照文档,但该文档根本没用。这只是一个充满例子的臃肿网站 我只需要一份护照使用的函数,类和变量列表,并解释它们和它们的每个参数的作用。每个好的图书馆都有这样的东西,为什么我找不到护照?

以下是我的代码的关键部分:

passport.use('local-signup', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    //are there other options?
    //emailField did not seem to do anything
    passReqToCallback: true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
    //check if email not already in database
        //create new user using "email" and "password"
        //I want an additional parameter here "name"
}));

护照真的那么有限吗?必须有办法做到这一点,对吗?

6 个答案:

答案 0 :(得分:21)

你可能有点困惑,但护照没有实施注册方法。它只是授权库。所以你必须自己处理这个用例。

首先,创建负责注册和检查的路线:

signup: function (req, res) {
  User
    .findOne({
      or: [{username: req.param('username')}, {email: req.param('email')}]
    })
    .then(function(user) {
      if (user) return {message: 'User already exists'};          
      return User.create(req.allParams());
    })
    .then(res.ok)
    .catch(res.negotiate);
}

上面的示例基于Sails框架,但您可以适应它而不会出现问题。

下一步是包括护照本地策略。

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

var LOCAL_STRATEGY_CONFIG = {
  usernameField: 'email',
  passwordField: 'password',
  session: false,
  passReqToCallback: true
};

function _onLocalStrategyAuth(req, email, password, next) {
  User
    .findOne(or: [{email: email}, {username: email}])
    .then(function (user) {
      if (!user) return next(null, null, {
        code: 'E_USER_NOT_FOUND',
        message: email + ' is not found',
        status: 401
      });

      if (!HashService.bcrypt.compareSync(password, user.password)) return next(null, null, {
        code: 'E_WRONG_PASSWORD',
        message: 'Password is wrong',
        status: 401
      });

      return next(null, user, {});
    })
    .catch(next);
}

passport.use(new LocalStrategy(LOCAL_STRATEGY_CONFIG), _onLocalStrategyAuth));

我们现在只有登录任务。这很简单。

signin: function(req, res) {
  passport.authenticate('local', function(error, user, info) {
    if (error || !user) return res.negotiate(Object.assign(error, info));
    return res.ok(user);
  })(req, res);
}

这种方式更适合护照,对我很有用。

答案 1 :(得分:4)

这对我有用,解决方案基于基于mongoose的odm,第一部分是护照相关部分,我还将用户部分从odm附加到谁如何加密密码。

如果我理解了您的问题,您希望用户输入他的电子邮件或密码。在这种情况下,修改搜索以尝试两者,即匹配提供的用户标识符(在使用用户名或密码调用findOne(...)时。

请注意,我使用bcrypt来避免存储明确的密码,这就是为什么有自定义比较方法来测试密码的原因。另请注意'提示'使用谷歌身份验证,我的系统启用两者,如果相关,请知道我可以添加所需的代码。

------------ Auth部分(只是相关的片段)-----------

var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;

passport.serializeUser(function(user, done) {
    // the values returned here will be used to deserializeUser
    // this can be use for further logins
    done(null, {username: user.username, _id: user.id, role: user.role});
});

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


passport.use(new LocalStrategy(function(username, password, done){
    odm.User.findOne({username: username, authType: 'direct'}, function(err, user){
        if(err){
            return done(err, false);
        }
        if(!user){
            return done(null, false);
        }
        if(user.role === 'new'){
            console.log('can not use new user!');
            return done('user not activated yet, please contact admin', false);
        }
        user.comparePassword(password,function(err, isMatch){
            if(err){
                return done(err, false);
            }
            if(isMatch){
                return done(null, user);//{username: username});
            }
            return done(null, false);
        });
    });
}));
app.post('/login',  function(req, res, next){
        passport.authenticate('local', {
            failureRedirect: '/logout?status=login failed'
        }, function(err, user, info){
                if(err){
                    return next(err);
                }
                if(!user){
                    return res.redirect('/login');
                }
                req.logIn(user, function(err){
                    if (req.body.rememberme) {
                        req.session.cookie.maxAge = 30*24*60*60*1000 ;//Rememeber 'me' for 30 days
                    } else {
                        req.session.cookie.expires = false;
                    }
                    var redirect = req.param('redirect') || '/index';
                    res.redirect(redirect);
                });
            }
        )(req, res, next);
    }
);

app.post('/register',function(req, res){
    var user = new odm.User({username: req.body.username, password: req.body.password, email: req.body.email, authType: 'direct'});
    user.save(function(err, user){
        if(err){
            console.log('registration err: ' , err);
        } else {
            res.redirect('/list');
        }
    });
});

--- user / odm,相关部分----------------

var bcrypt = require('bcrypt-nodejs');

// --------------------- User ------------------------------------------ //
var userSchema = new Schema({
    name: String,
    email: String,
    username: {type: String, required: true, unique: true},
    password: String,
    role: {type: String, required: true, enum: ['new', 'admin', 'user'], default: 'new'},
    authType: {type: String, enum: ['google', 'direct'], required: true}
});

userSchema.pre('save', function (next) {
    var user = this;
    if (!user.isModified('password')) return next();

    console.log('making hash...........');
    bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {
        if (err) return next(err);

        bcrypt.hash(user.password, salt, null, function (err, hash) {
            if (err) return next(err);
            user.password = hash;
            next();
        });
    });
});

userSchema.methods.comparePassword = function (candidatePassword, cb) {
    bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
        if (err) return cb(err);
        cb(null, isMatch);
    });
};

答案 2 :(得分:4)

说你有这个

app.post('/login', urlencodedParser,
    // so, user has been to /loginpage and clicked submit.
    // /loginpage has a post form that goes to "/login".
    // hence you arrive here.
    passport.authenticate('my-simple-login-strategy', {
        failureRedirect: '/loginagain'
    }),
        function(req, res) {
            console.log("you are in ............")
            res.redirect('/stuff');
    });

请注意,.authenticate有一个显式标签。

标签为'my-simple-login-strategy'

那意味着你有这个...

passport.use(
    'my-simple-login-strategy',
    // !!!!!!!!!!!!!note!!!!!!!!!!, the DEFAULT there (if you have nothing)
    // is 'local'. A good example of defaults being silly :/
    new Strategy(
        STRAT_CONFIG,
        function(email, password, cb) {
           // must return cb(null, false) or cb(null, the_user_struct) or cb(err)
           db.findUserByEmailPass(email, password, function(err, userFoundByDB) {
                if (err) { return cb(err); }
                if (!userFoundByDB) { return cb(null, false); }
                console.log('... ' + JSON.stringify(userFoundByDB) )
                return cb(null, userFoundByDB)
           })
        }
    )
)

!!! !!!请注意,“本地”只是默认标记名称! !!!

passport.use中,我们总是放置一个显式标签。如果这样做,则更加清楚。使用策略时,请在策略中以及app.post中添加显式标签。

这就是我的简单登录策略。

实际的db.findUserByEmailPass sql函数是什么?

我们将回到这一点!

所以我们有我的简单登录策略

下一步......我们需要my-simple-createaccount-strategy

请注意,我们仍在偷偷使用passport.authenticate:

所以:

my-simple-createaccount-strategy策略实际上将创建一个帐户。

但是.............

您仍然应该返回一个结构。

请注意,我的简单登录策略必须返回一个结构。

因此,my-simple-createaccount-strategy还必须以完全相同的方式返回结构。

app.post('/createaccount', urlencodedParser,
    // so, user has been to /createanaccountform and clicked submit,
    // that sends a post to /createaccount. So we are here:
    passport.authenticate('my-simple-createaccount-strategy', {
        failureRedirect: '/loginagain'
    }),
        function(req, res) {
            console.log("you are in ............")
            res.redirect('/stuff');
    });

这是策略..........

passport.use(
    'my-simple-createaccount-strategy',
    new Strategy(
        STRAT_CONFIG,
        function(email, password, cb) {
            // return cb(null, false), or cb(null, the_user_struct) or cb(err)
            db.simpleCreate(email, password, function(err, trueOrFalse) {
                if (err) { return cb(err); }
                if (!trueOrFalse) { return cb(null, false); }
                return cb(null, trueOrFalse)
            })
        }
    )
)

策略几乎相同。但是数据库调用不同。

现在让我们看一下数据库调用。

让我们看一下数据库调用!

用于普通策略的普通db调用看起来像这样:

exports.findUserByEmailPass = function(email, password, cb) {
    // return the struct or false via the callback
    dc.query(
        'select * from users where email = ? and password = ?',
        [email, password],
        (error, users, fields) => {
            if (error) { throw error } // or something like cb(new Error('blah'));
            cb(null, (users.length == 1) ? users[0] : false)
        })
}

这就是export.findUserByEmailPass,它由my-simple-login-strategy使用。

但是对于my-simple-createaccount-strategy,exports.simpleCreate呢?

一个简单的玩具版本会

  1. 检查用户名是否已经存在-如果该用户名已经存在,则在此时返回false,然后
  2. 创建它,然后
  3. 实际上只是再次返回记录。

回想一下(3)就像在普通的“ find”调用中一样。

记住... 该策略my-simple-createaccount-strategy实际上会建立一个帐户。但是您仍然应该相同的方式返回一个结构,作为您的普通身份验证策略,即my-simple-login-strategy。

因此exports.simpleCreate是三个调用的简单链:

exports.simpleCreate = function(email, password, cb) {
    // check if exists; insert; re-select and return it
    dc.query(
        'select * from users where email = ?', [email],
        (error, users, fields) => {
            if (error) { throw error } // or something like cb(new Error('blah'));
            if (users.length > 0) {
                return cb(null, false)
            }  
            else {
                return partTwo(email, password, cb)
            }
        })
}

partTwo = function(email, password, cb) {
    dc.query(
        'insert into users (email, password) values (?, ?)', [email, password],
        (error, users, fields) => {
            if (error) { throw error } // or something like cb(new Error('blah'));
            partThree(email, password, cb)
        })
}

partThree = function(email, password, cb) {
    dc.query(
        'select * from users where email = ? and password = ?', [email, password],
        (error, users, fields) => {
            if (error) { throw error } // or something like cb(new Error('blah'));
            cb(null, (users.length == 1) ? users[0] : false)
        })
}

一切正常。

但是请注意

护照与帐户创建没有任何关系!

实际上,您根本不必使用策略。

如果需要,您可以在app.post('/createaccount'中使用passport.authenticate不执行任何操作……甚至不用在代码中提及它。根本不使用身份验证。只需继续进行操作,就可以在app.post中执行插入新用户的sql过程。

但是,如果您“细心地”使用护照策略(本例中为my-simple-createaccount-strategy),您将获得额外的好处,那就是用户可以立即通过会话登录,并且一切操作都与登录信息。很好。

答案 3 :(得分:1)

var localStrategy = require('passport-local').Strategy;
var User = require('../public/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('local-signup', new localStrategy({
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true
    },
    function(req, email, password, done){
        process.nextTick(function(){
             User.findOne({'local.enroll': email}, function(err, user){
                 if(err)
                     return done(err);
                 if(user){
                     return done(null, false, req.flash('signupmessage', 'The email already taken'));
                 } else{
                     var newUser = new User();
                     newUser.local.enroll = email;
                     newUser.local.password = newUser.generateHash(password);                     
                     newUser.save(function(err){
                         if(err)
                             throw err
                         return done(null, newUser);
                     });
                 }

             });
        });
    }));

    passport.use('local-login', new localStrategy({
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true
    },
    function(req, email, password, done){
        process.nextTick(function(){
             User.findOne({'local.enroll': email}, function(err, user){
                 if(err)
                     return done(err);
                 if(!user){
                     return done(null, false, req.flash('loginmessage', 'No user found'));
                 }
                 if(!user.validPassword(password)){
                     return done(null, false, req.flash('loginmessage', 'Invalid password'));
                 }
                 return done(null, user);
             });
        });
    }));    
}

答案 4 :(得分:1)

这实际上与passport没有任何关系,并且非常简单(假设您正在使用body-parser)。确保您的表单中有一个input field属性为name="name"的{​​{1}},在其中注册用户名,例如:

<div class="form-group">
    <label for="signup-name">Name</label>
    <input type="text" placeholder="Name" name="name">
</div> 

在路由中,您可以使用req.body.name访问此字段:

passport.use('local-signup', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    //are there other options?
    //emailField did not seem to do anything
    passReqToCallback: true
},
function(req, email, password, done) {
    //check if email not already in database
    //create new user using "email" and "password"
    //I want an additional parameter here "name"

    user.email = email;
    user.password = password; // Do some hashing before storing

    user.name = req.body.name;

}));

因此,您可以根据需要添加任意多个表单输入字段,并通过name属性的值进行访问。第二个示例是:

<input type="text" placeholder="City" name="city">
<input type="text" placeholder="Country" name="country">

// Access them by
user.city = req.body.city;
user.country = req.body.country;

答案 5 :(得分:0)

UserModel.find({email: req.body.email}, function(err, user){                                               
    if(err){                                                                  
       res.redirect('/your sign up page');                                                                          
    } else {                                                                  
      if(user.length > 0){                                                    
       res.redirect('/again your sign up page');                                                                      
      } else{                                                               
        //YOUR REGISTRATION CODES HERE                                                                     
       }                                                                          
    }                                                                        
})
相关问题