Подтвердить что ты не робот

Как защитить поле пароля в Mongoose/MongoDB, чтобы он не возвращался в запрос при заполнении коллекций?

Предположим, что у меня есть две коллекции/схемы. Одна из них - это схема пользователей с полями имени пользователя и пароля, затем у меня есть схема блогов, в которой есть ссылка на схему пользователей в поле автора. Если я использую Mongoose, чтобы сделать что-то вроде

Blogs.findOne({...}).populate("user").exec()

У меня будет документ в блоге и пользователь, который заполняется, но как я могу запретить Mongoose/MongoDB возвращать поле пароля? Поле пароля хэшируется, но оно не должно быть возвращено.

Я знаю, что могу опустить поле пароля и возвращать остальные поля в простой запрос, но как это сделать с заполнением. Кроме того, есть ли элегантный способ сделать это?

Кроме того, в некоторых ситуациях мне нужно получить поле пароля, например, когда пользователь хочет войти или изменить пароль.

4b9b3361

Ответ 1

.populate('user' , '-password')

http://mongoosejs.com/docs/populate.html

Ответ JohnnyHKs с использованием опций схемы, вероятно, является способом перехода сюда.

Также обратите внимание, что query.exclude() существует только в ветке 2.x.

Ответ 2

Вы можете изменить поведение по умолчанию на уровне определения схемы с помощью атрибута select поля:

password: { type: String, select: false }

Затем вы можете потянуть его по мере необходимости в сообщениях find и populate с помощью выбора поля в качестве '+password'. Например:

Users.findOne({_id: id}).select('+password').exec(...);

Ответ 3

Изменить:

Попробовав оба подхода, я обнаружил, что исключающий всегда подход не работает для меня по какой-то причине с использованием паспортно-локальной стратегии, не знаю почему.

Итак, вот что я в итоге использовал:

Blogs.findOne({_id: id})
    .populate("user", "-password -someOtherField -AnotherField")
    .populate("comments.items.user")
    .exec(function(error, result) {
        if(error) handleError(error);
        callback(error, result);
    });

Нет ничего плохого в том, что исключение всегда подходит, оно почему-то не срабатывало с паспортом, мои тесты сказали мне, что на самом деле пароль был исключен/включен, когда я захотел. Единственная проблема с включением всегда заключается в том, что мне в основном нужно пройти каждый вызов, который я делаю в базе данных, и исключить пароль, который является большой работой.


После нескольких отличных ответов я обнаружил, что есть два способа сделать это: "всегда включать и исключать иногда" и "всегда исключать и включать иногда"?

Пример обоих:

Включить всегда, но исключать иногда пример:

Users.find().select("-password")

или

Users.find().exclude("password")

exlucde всегда, но иногда включает пример:

Users.find().select("+password")

но вы должны определить в схеме:

password: { type: String, select: false }

Ответ 4

User.find().select('-password') - правильный ответ. Вы не можете добавить select: false в схему, поскольку она не будет работать, если вы хотите войти в систему.

Ответ 5

Вы можете добиться этого, используя схему, например:

const UserSchema = new Schema({/* */})

UserSchema.set('toJSON', {
    transform: function(doc, ret, opt) {
        delete ret['password']
        return ret
    }
})

const User = mongoose.model('User', UserSchema)
User.findOne() // This should return an object excluding the password field

Ответ 6

Предполагая, что ваше поле пароля является "паролем", вы можете просто сделать:

.exclude('password')

Ниже представлен более обширный пример здесь

Это сосредоточено на комментариях, но это тот же самый принцип в игре.

Это то же самое, что использовать проекцию в запросе в MongoDB и передавать {"password" : 0} в поле проекции. См. здесь

Ответ 7

Решение состоит в том, чтобы никогда не хранить незашифрованные пароли. Вам следует использовать такой пакет, как bcrypt или хэш пароля.

Пример использования для хеширования пароля:

 var passwordHash = require('password-hash');

    var hashedPassword = passwordHash.generate('password123');

    console.log(hashedPassword); // sha1$3I7HRwy7$cbfdac6008f9cab4083784cbd1874f76618d2a97

Пример использования для подтверждения пароля:

var passwordHash = require('./lib/password-hash');

var hashedPassword = 'sha1$3I7HRwy7$cbfdac6008f9cab4083784cbd1874f76618d2a97';

console.log(passwordHash.verify('password123', hashedPassword)); // true
console.log(passwordHash.verify('Password0', hashedPassword)); // false

Ответ 8

Я использую поле скрытого пароля в ответе REST JSON

UserSchema.methods.toJSON = function() {
 var obj = this.toObject();
 delete obj.password;
 return obj;
}

module.exports = mongoose.model('User', UserSchema);

Ответ 9

Вы можете передать объект DocumentToObjectOptions в schema.toJSON() или schema.toObject().

См. определение TypeScript из @types/mongoose

 /**
 * The return value of this method is used in calls to JSON.stringify(doc).
 * This method accepts the same options as Document#toObject. To apply the
 * options to every document of your schema by default, set your schemas
 * toJSON option to the same argument.
 */
toJSON(options?: DocumentToObjectOptions): any;

/**
 * Converts this document into a plain javascript object, ready for storage in MongoDB.
 * Buffers are converted to instances of mongodb.Binary for proper storage.
 */
toObject(options?: DocumentToObjectOptions): any;

DocumentToObjectOptions имеет параметр преобразования, который запускает пользовательскую функцию после преобразования документа в объект javascript. Здесь вы можете скрыть или изменить свойства в соответствии с вашими потребностями.

Итак, допустим, вы используете schema.toObject() и хотите скрыть путь к паролю из вашей пользовательской схемы. Вы должны настроить общую функцию преобразования, которая будет выполняться после каждого вызова toObject().

UserSchema.set('toObject', {
  transform: (doc, ret, opt) => {
   delete ret.password;
   return ret;
  }
});

Ответ 10

Blogs.findOne({ _id: id }, { "password": 0 }).populate("user").exec()

Ответ 11

При использовании password: { type: String, select: false } вы должны иметь в виду, что он также будет исключать пароль, когда он нам понадобится для аутентификации. Поэтому будьте готовы обращаться с ним, как хотите.

Ответ 12

Это скорее следствие первоначального вопроса, но это был вопрос, с которым я столкнулся, пытаясь решить мою проблему...

А именно, как отправить пользователя обратно клиенту в обратном вызове user.save() без поля пароля.

Случай использования: пользователь приложения обновляет информацию/настройки своего профиля от клиента (пароль, контактную информацию, whatevs). Вы хотите отправить обновленную информацию о пользователе обратно клиенту в ответ, как только он успешно будет сохранен в mongoDB.

User.findById(userId, function (err, user) {
    // err handling

    user.propToUpdate = updateValue;

    user.save(function(err) {
         // err handling

         /**
          * convert the user document to a JavaScript object with the 
          * mongoose Document toObject() method,
          * then create a new object without the password property...
          * easiest way is lodash _.omit function if you're using lodash 
          */

         var sanitizedUser = _.omit(user.toObject(), 'password');
         return res.status(201).send(sanitizedUser);
    });
});

Ответ 13

Я нашел другой способ сделать это, добавив некоторые настройки в конфигурацию схемы.

const userSchema = new Schema({
    name: {type: String, required: false, minlength: 5},
    email: {type: String, required: true, minlength: 5},
    phone: String,
    password: String,
    password_reset: String,
}, { toJSON: { 
              virtuals: true,
              transform: function (doc, ret) {
                delete ret._id;
                delete ret.password;
                delete ret.password_reset;
                return ret;
              }

            }, timestamps: true });

Добавив функцию преобразования в объект toJSON с именем поля, которое нужно исключить. как указано в документах:

Нам может потребоваться выполнить преобразование результирующего объекта на основе по некоторым критериям, скажем, удалить некоторую конфиденциальную информацию или вернуть пользовательский объект. В этом случае мы устанавливаем дополнительную функцию transform.