MongoDB представляет собой документоориентированную NoSQL базу данных, в которой данные хранятся в формате BSON-документов. В связке с Node.js-экосистемой часто используется Mongoose — ODM-библиотека, обеспечивающая структурирование данных, валидацию и удобные хуки жизненного цикла документов.
При работе с паролями в MongoDB ключевая задача заключается не в
хранении исходного значения, а в сохранении его криптографического хэша.
Библиотека password-hash реализует простой механизм
хеширования и проверки пароля, предоставляя готовые функции генерации и
валидации строкового представления хэша.
Структура документа пользователя обычно минимально включает идентификатор, email и поле для хранения пароля в виде хэша.
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true
},
password: {
type: String,
required: true
}
});
В данном случае поле password никогда не содержит
исходный текст, а хранит результат работы
password-hash.
Библиотека password-hash предоставляет две ключевые
функции:
generate(password) — создание хэшаverify(password, hashedPassword) — проверка
соответствияИнтеграция выполняется через middleware Mongoose.
const passwordHash = require('password-hash');
UserSchema.pre('save', function(next) {
if (!this.isModified('password')) return next();
this.password = passwordHash.generate(this.password);
next();
});
Логика проверки isModified предотвращает повторное
хеширование уже захешированного значения при обновлении других полей
документа.
Для аутентификации используется метод экземпляра модели, который сравнивает введённый пароль с сохранённым хэшем.
UserSchema.methods.comparePassword = function(candidatePassword) {
return passwordHash.verify(candidatePassword, this.password);
};
Такой подход инкапсулирует логику проверки внутри модели, исключая дублирование кода в сервисах аутентификации.
Процесс создания пользователя становится линейным: перед сохранением пароль автоматически преобразуется в хэш.
const User = mongoose.model('User', UserSchema);
async function registerUser(email, password) {
const user = new User({ email, password });
await user.save();
return user;
}
После выполнения save() в базе данных хранится только
хэшированное значение.
Проверка учетных данных выполняется через поиск пользователя и вызов метода сравнения.
async function authenticate(email, password) {
const user = await User.findOne({ email });
if (!user) return false;
const isValid = user.comparePassword(password);
return isValid ? user : false;
}
При успешной проверке возвращается объект пользователя, при неудачной — отрицательный результат.
Особое внимание требуется при изменении пароля. Поскольку
используется middleware pre('save'), любое изменение поля
password автоматически приводит к повторному
хешированию.
async function updatePassword(userId, newPassword) {
const user = await User.findById(userId);
user.password = newPassword;
await user.save();
}
Важно, что повторное применение passwordHash.generate
происходит только при сохранении, а не при присвоении значения.
При переходе существующего проекта на использование
password-hash необходимо учитывать:
Пример гибридной проверки:
UserSchema.methods.comparePassword = function(candidatePassword) {
const isHashed = this.password.includes('sha1'); // условная проверка формата
if (isHashed) {
return passwordHash.verify(candidatePassword, this.password);
}
if (candidatePassword === this.password) {
this.password = passwordHash.generate(candidatePassword);
this.save();
return true;
}
return false;
};
Использование password-hash отличается простотой, но
имеет архитектурные ограничения:
В высоконагруженных системах с требованиями к безопасности обычно применяются альтернативы, однако интеграционная модель с Mongoose остаётся аналогичной: middleware + метод сравнения.
В архитектуре приложения логика работы с паролями обычно разделяется:
Такое разделение снижает связанность компонентов и упрощает тестирование.
Node.js обеспечивает неблокирующую модель выполнения, поэтому
операции с MongoDB и Mongoose выполняются через Promise или async/await.
Несмотря на синхронный интерфейс password-hash, его
использование внутри middleware не блокирует основной поток критическим
образом при малых и средних нагрузках.
При интеграции важно учитывать корректную обработку исключений:
UserSchema.pre('save', function(next) {
if (!this.password || this.password.length < 6) {
return next(new Error('Некорректный пароль'));
}
next();
});
При увеличении нагрузки логика хеширования часто выносится:
Тем не менее, интеграционная модель Mongoose остаётся стабильной: схема + middleware + методы экземпляра.