#node.js #authentication
#node.js #аутентификация
Вопрос:
У меня есть система входа / регистрации в Node, которая работает просто отлично. Однако на данный момент пользователь может входить в систему только через свою электронную почту, но я хочу, чтобы пользователь мог входить в систему либо по электронной почте, либо по имени пользователя. Я считаю, что проблема существует в моей модели (моя система использует подход MVC), но я также включу соответствующий код контроллера.
userController.js
module.exports.post_login = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.login(email, password);
const token = createToken(user._id);
res.cookie('jwt', token, { httpOnly: true, maxAge: maxAge * 1000 });
res.status(200).json({ user: user._id });
}
catch (err) {
const errors = handleErrors(err);
res.status(400).json({ errors });
}
}
userModel.js
const userSchema = new mongoose.Schema({
//some user schema code that works just fine
});
userSchema.pre('save', async function(next) {
const salt = await bcrypt.genSalt();
this.password = await bcrypt.hash(this.password, salt);
next();
});
// static method to login user
userSchema.statics.login = async function(email, password) {
const user = await this.findOne({ email });
if (user) {
const auth = await bcrypt.compare(password, user.password);
if (auth) {
return user;
}
throw Error('incorrect password');
}
throw Error('incorrect email');
};
const User = mongoose.model('user', userSchema);
module.exports = User;
Здесь позвольте мне включить файл просмотра. Извините за это.
login.ejs
<form action='/register' class="form" method='POST'>
<div id='login'>
<h1>Greetings!<h1>
<h4>We're so happy you've returned.<h4>
<div class="input-group">
<input type="text" name="email" autocomplete='off'
placeholder="Username or Email Address" required />
</div>
<div class="email error"></div>
<div class="input-group">
<input type="password" name="password"
placeholder="Password" autocomplete='off'
required />
<div class="password error"></div>
</div>
<button type='submit' class='btn'><span>Login</span></button><br />
<p>
<h6><u><a href="forgot-password.php">Forgot Password?</a></u></h6>
</form>
</div>
<script>
const form = document.querySelector('form')
//const usernameError = document.querySelector('.username.error')
const emailError = document.querySelector('.email.error')
const passwordError = document.querySelector('.password.error')
form.addEventListener('submit', async (e)=>{
e.preventDefault();
//reset errors
/*usernameError.textContent =*/ emailError.textContent = passwordError.textContent = '';
// get values
//const username = form.username.value
const email = form.email.value
const password = form.password.value
try {
const res = await fetch('/login', {
method: 'POST',
body: JSON.stringify({ email, password }),
headers: {'Content-Type': 'application/json'}
})
const data = await res.json()
console.log(data)
if(data.errors){
//usernameError.textContent = data.errors.username
emailError.textContent = data.errors.email
passwordError.textContent = data.errors.password
}
if(data.user){
location.assign('/profile')
}
}
catch (err) {
console.log(err)
}
})
</script>
Я понимаю, что в контроллере мне нужно добавить имя пользователя при запросе тела и в инструкции try, но я подожду, чтобы увидеть, что вы, ребята / девушки, предлагаете.
Проблема, вероятно, существует в модели при методе findOne(): const user = await this.findOne({ email });
.
Я просто не уверен, какой метод использовать вместо этого, и я бы предпочел отложить ваши предложения о том, как включить массив в это место (я предполагаю, что мне понадобится username, email
тип массива).). Любая помощь будет оценена. Если вам нужно больше кода, пожалуйста, дайте мне знать, и я его предоставлю. Спасибо!
Комментарии:
1.
$or:
не работает. Проблема в том, что в login.ejs я определяю «email» какconst email = form.email.value
, но у меня нет ничего в форме для определения имени пользователя. Как мне извлечь имя пользователя из коллекции MongoDB, а не из формы?
Ответ №1:
вам нужно найти пользователя по его имени пользователя или электронной почте, я думаю, это может помочь заменить
const user = await this.findOne({ email });
Автор:
const user = await this.findOne(
{
$or: [
{ email },{ username }
]
}
)
имя пользователя должно считываться из тела запроса, как вы говорите
Комментарии:
1. Спасибо, я еще не запустил код, но завтра я это сделаю. Просто сообщаю вам, что я включил файл просмотра (login.ejs), который, я думаю, также может помочь. Извините, я забыл об этом.
Ответ №2:
Если я правильно понял, у вас есть один ввод, который может содержать имя пользователя или адрес электронной почты. Я бы предложил получить это значение и получить пользователя с помощью оператора or.
таким образом, вы передаете только входное значение в качестве параметра и извлекаете пользователя.
const user = await this.findOne({ $or: [ {email: value}, {username: value} ] });
Комментарии:
1. Спасибо, я еще не запустил код, но завтра я это сделаю. Просто сообщаю вам, что я включил файл просмотра (login.ejs), который, я думаю, также может помочь. Извините, я забыл об этом.