有没有办法允许用户使用他的密码,电子邮件和姓名注册本地策略?
我在网上找到的每个例子都只使用名称/密码或电子邮件/密码。
我还搜索了整个护照文档,但该文档根本没用。这只是一个充满例子的臃肿网站 我只需要一份护照使用的函数,类和变量列表,并解释它们和它们的每个参数的作用。每个好的图书馆都有这样的东西,为什么我找不到护照?
以下是我的代码的关键部分:
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"
}));
护照真的那么有限吗?必须有办法做到这一点,对吗?
答案 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函数是什么?
我们将回到这一点!
请注意,我们仍在偷偷使用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呢?
一个简单的玩具版本会
回想一下(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
}
}
})