我有一个带护照的node.js登录系统,但我试图弄清楚如何用用户名或电子邮件登录用户。我只能单独使用电子邮件或用户名登录用户。我不知道如何编写代码来满足用户名和电子邮件的需求。因此,如果用户想要使用用户名登录,他们可以或者如果希望使用他们的电子邮件,他们也可以。这是我的users.js文件中的localstrategy代码:
passport.use(new LocalStrategy(
function(email, password, done) {
User.getUserByEmail(email, function(err, user, next){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown user'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
这是我的module.exports在我的user.js:
module.exports.getUserByEmail = function(email, callback){
var query = {email: email};
User.findOne(query, callback);
}
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
}
以上代码仅允许用户使用他们的电子邮件登录。我希望用户有机会使用他们的电子邮件或用户名登录。
答案 0 :(得分:0)
您可以在getUserById
的回调中使用getUserByEmail
,以便同时针对email
或username
运行这两个查询。如果您指定email
,则emailOrUserName
将具有email
值,然后User.getUserByEmail
将返回用户,然后它将继续comparePassword
。
如果您有username
,则emailOrUserName
将具有username
值,然后User.getUserByEmail
将不会返回用户,因此会执行User.getUserById
并且在那里找到用户然后它将继续User.comparePassword
否则它将返回Unknown user
passport.use(new LocalStrategy(
function(emailOrUserName, password, done) {
User.getUserByEmail(emailOrUserName, function(err, user, next){
if(err) throw err;
if(!user){
User.getUserById(emailOrUserName, function(err, user, next){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown user'});
}
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
答案 1 :(得分:0)
在身份验证中间件中期望 username
和password
,然后继续使用找到的任何值作为找到用户的条件。
中间件示例:
function authenticateUser(req, res, done) {
let username = req.body.username,
password = req.body.password,
email = req.body.email;
let conditions = !!username ? {username: username} : {email: email};
UserModel.findOne(conditions, (err, user) => {
if (err) return done(err);
if (!user) return done(new Error('Incorrect username or email'));
return user.comparePassword(password, user.password)
.then(match => {
if (match) return done();
else return done(new Error('Incorrect password'));
})
.catch(error => {
if (error) return done(new Error(`Unable to validated password. - ${error}`));
});
});
}
现在,拥有正确文档的前端开发人员现在可以实际使用username
,email
或两者(您将需要一些JavaScript)两者)在使用端点构建登录表单时。这是同时使用两者的示例:
HTML:
<form id="login-form" method="POST" action="/login">
<input id="username-or-email" type="text" placeholder="Username or Email" required/>
<input type="password" name="password" placeholder="Password" required/>
<input type="submit"/>
</form>
JavaScript:
// select the form element
let loginForm = document.querySelector('#login-form');
// add a form handler on submit
loginForm.addEventListener("submit", formHandler);
// validate and the set name attribute as appropriate
function formHandler() {
/** W3C Email regex: (RFC5322) */
const email_regex = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
/** Must starts with a letter then can include underscores (_) & hyphens (-) */
const username_regex = /^[a-zA-Z][\w-]+$/;
let input = document.querySelector('#username-or-email');
if (email_regex.test(input.value)) {
// it is an email, send the value as an email
input.setAttribute("name", "email");
} else if (username_regex.test(input.value)) {
// it is a username, send the value as a username
input.setAttribute("name", "username");
} else {
// invalid email or username format, return an error message to user
}
}
因此,您可以同时验证和设置动态输入。请记住,正则表达式应尽可能匹配您的用户名和电子邮件数据模型。
答案 2 :(得分:0)
按照当地策略进行
function(username, password, done) {
var criteria = (username.indexOf('@') === -1) ? {username: username} : {email: username};
User.findOne(criteria, function (err, user) { //implementation }
答案 3 :(得分:0)
刚刚进入这种情况,我虽然会分享我的最终代码以使用用户名或电子邮件来验证用户:
userSchema.statics.findByCredentials = async credentials => {
const {
email = undefined,
username = undefined,
password = undefined
} = credentials
if ((!!email && !!username) || (!email && !username)) {
throw new Error('Should provide either email or username.')
}
if (!password) {
throw new Error('Password is required.')
}
const user = await User.findOne(email ? { email } : { username })
if (!user) {
throw new Error('Credentials are invalid!')
}
if (!bcrypt.compare(password, user.password)) {
throw new Error('Credentials are invalid!')
}
return user
}
所以我使用这个函数来验证用户是否提供了有效的凭据,并从我的处理程序中调用 model 类上的函数。