[英]Node.js Passport strategy login with either Email or Username
I am using Passport on my node.js app and I am currently using an Username to login.我在我的 node.js 应用程序上使用 Passport,我目前正在使用用户名登录。
On my user register page, I have allow the user to register their unique username and email.在我的用户注册页面上,我允许用户注册他们唯一的用户名和电子邮件。
I want a login page with "Sign in Using username/email:" _ __ _ __ _ _我想要一个带有“使用用户名/电子邮件登录:”的登录页面: _ __ _ __ _ _
Where the script can detect if there is a "@" in the field and look up the email instead of username.脚本可以检测字段中是否有“@”并查找电子邮件而不是用户名。
I have tried for a few hours with no avail.我已经尝试了几个小时但无济于事。
here is my passport.js这是我的passport.js
var mongoose = require('mongoose')
var LocalStrategy = require('passport-local').Strategy
var User = mongoose.model('User');
module.exports = function(passport, config){
passport.serializeUser(function(user, done){
done(null, user.id);
})
passport.deserializeUser(function(id, done) {
User.findOne({ _id: id }, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
}, function(username, password, done) {
User.isValidUserPassword(username, password, done);
}));
}
EDIT: below is the user.js as requested编辑:下面是请求的 user.js
var mongoose = require('mongoose');
var hash = require('../util/hash.js');
UserSchema = mongoose.Schema({
username: String,
email: String,
salt: String,
hash: String
})
UserSchema.statics.signup = function(username, email, password, done){
var User = this;
hash(password, function(err, salt, hash){
if(err) throw err;
// if (err) return done(err);
User.create({
username : username,
email: email,
salt : salt,
hash : hash
}, function(err, user){
if(err) throw err;
// if (err) return done(err);
done(null, user);
});
});
}
UserSchema.statics.isValidUserPassword = function(username, password, done) {
this.findOne({username : username}, function(err, user){
// if(err) throw err;
if(err) return done(err);
if(!user) return done(null, false, { message : 'Incorrect username.' });
hash(password, user.salt, function(err, hash){
if(err) return done(err);
if(hash == user.hash) return done(null, user);
done(null, false, {
message : 'Incorrect password'
});
});
});
};
var User = mongoose.model("User", UserSchema);
module.exports = User;
Ok, you should have something like this in your Mongoose model:好的,你的猫鼬模型中应该有这样的东西:
UserSchema.statics.isValidUserPassword = function(username, password, done) {
var criteria = (username.indexOf('@') === -1) ? {username: username} : {email: username};
this.findOne(criteria, function(err, user){
// All the same...
});
};
its a mongoose thing rather than a passport thing, and if you can try out this, using bredikhin's answer ^_^ :它是猫鼬的东西而不是护照的东西,如果您可以尝试一下,请使用 bredikhin 的回答 ^_^ :
var criteria = {$or: [{username: username}, {email: username}, {mobile: username}, {anything: username}]};
The key is to find a user through a query from mongodb!!!关键是通过mongodb的查询找到用户!!!
In this way, you can have whatever query you want to find a user.通过这种方式,您可以进行任何想要查找用户的查询。
For sign ins with username OR email, you could also use passport-local-mongoose
's findByUsername option modify the queryParameters对于使用用户名或电子邮件登录,您还可以使用passport-local-mongoose
mongoose 的 findByUsername 选项修改queryParameters
// add passport functions
// schema.plugin(passportLocalMongoose);
schema.plugin(passportLocalMongoose, {
// allow sign in with username OR email
findByUsername: function(model, queryParameters) {
// start
// // queryParameters => { '$or' : [ { 'username' : 'searchString' } ] }
// iterate through queryParameters
for( let param of queryParameters.$or ){
// if there is a username
if( typeof param == "object" && param.hasOwnProperty("username") ){
// add it as an email parameter
queryParameters.$or.push( { email : param.username } );
}
}
// expected outcome
// queryParameters => { '$or' : [ { 'username' : 'searchString' }, { 'email' : 'searchString' } ] }
return model.findOne(queryParameters);
}
});
its very simple you have to redefine the passport strategy your self, just like in the code below,它非常简单,您必须自己重新定义护照策略,就像下面的代码一样,
serialize with username用用户名序列化
passport.serializeUser(function(user, done) {
done(null, user.username);});
deserialize with username使用用户名反序列化
passport.deserializeUser(function(username, done) {
User.findOne({username:username},function(err, user){
done(err,user);
}); });
Passport Strategy护照攻略
//passport strategy
passport.use(new LocalStrategy(function(username, password, done) {
console.log(username.includes("@"));
User.findOne((username.includes("@"))?{email:username}:{username:username}, function(err, user) {
if (err) {return done(err); }
if (!user) {console.log("i am ERROR"); return done(null, false, { message: 'Incorrect username.' });}
if (user.password===password) {return done(null, user); }
return done(null, false);
});
}
));
NOTE: Here user.password===password
means that the password in database is stored as plaintext.. And you have to insert password manually to database such as password : req.body.password
also you have to apply encryption and decryption user self before adding or in comparing.注意:这里user.password===password
表示数据库中的密码以明文形式存储..并且您必须手动将密码插入数据库,例如password : req.body.password
您还必须应用加密和解密 user self在添加或比较之前。
Or you just make a middle-ware to handle the situation like so:或者你只是制作一个中间件来处理这样的情况:
const User = require("../models/user");
var middlewareObj = {};
middlewareObj.checkUsername = function (req, res, next) {
if (req.body.username.indexOf('@') !== -1) {
User.findOne({ email: req.body.username }, (err, foundUser) => {
if (err || !foundUser) {
req.flash('error', 'Please check your username or password');
return res.redirect('/login');
} else {
req.body.username = foundUser.username;
next();
}
});
} else {
next();
}
}
module.exports = middlewareObj;
And simply add it to the login route:只需将其添加到登录路由:
app.post('/login', middleware.checkUsername, function (req, res, next) {
//Login logic goes here
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.