首页 文章

如何保护Mongoose / MongoDB中的密码字段,以便在填充集合时不会在查询中返回?

提问于
浏览
58

假设我有两个集合/模式 . 一个是带有用户名和密码字段的用户架构,然后,我有一个Blogs架构,它在作者字段中引用了用户架构 . 如果我使用Mongoose做类似的事情

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

我也会有Blog文档和用户填充,但是如何阻止Mongoose / MongoDB返回密码字段?密码字段经过哈希处理,但不应返回 .

我知道我可以省略密码字段并在简单查询中返回其余字段,但是我如何使用populate执行此操作 . 另外,有没有优雅的方法来做到这一点?

此外,在某些情况下,我需要获取密码字段,例如当用户想要登录或更改密码时 .

11 回答

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

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

    JohnnyHKs使用Schema选项回答可能就是这里的方法 .

    另请注意, query.exclude() 仅存在于2.x分支中 .

  • 47

    您可以使用字段的select属性更改架构定义级别的默认行为:

    password: { type: String, select: false }
    

    然后你可以根据需要在 findpopulate 调用中通过字段选择将其拉入 '+password' . 例如:

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

    编辑:

    在尝试了这两种方法之后,我发现排除总是方法因为某种原因使用护照本地策略不适合我,不知道为什么 .

    所以,这就是我最终使用的:

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

    排除总是方法没有任何问题,由于某种原因,它只是没有使用护照,我的测试告诉我,实际上密码被排除/包含在我想要的时候 . 包含总是方法的唯一问题是我基本上需要经历我对数据库的每次调用并排除密码,这是很多工作 .


    经过几个很好的答案,我发现有两种方法可以做到这一点,“总是包括和排除有时”和“总是排除和有时包括”?

    两者的一个例子:

    The include always but exclude sometimes 示例:

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

    要么

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

    The exlucde always but include sometimes 示例:

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

    但您必须在架构中定义:

    password: { type: String, select: false }
    
  • 0

    User.find().select('-password') 是正确的答案 . 如果要登录,则无法在架构上添加 select: false ,因为它不起作用 .

  • 4

    假设您的密码字段是“密码”,您可以这样做:

    .exclude('password')
    

    有一个更广泛的例子here

    这是关注评论,但它是相同的原则 .

    这与在MongoDB中使用查询中的投影并在投影字段中传递 {"password" : 0} 相同 . 见here

  • 2

    您可以使用模式实现该目标,例如:

    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
    
  • 0

    解决方案是永远不存储明文密码 . 你应该使用像 [bcrypt] 1[password-hash] 2这样的包 .

    哈希密码的示例用法:

    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
    
  • 6

    这更像是原始问题的必然结果,但这是我遇到的问题,试图解决我的问题......

    Namely, how to send the user back to the client in the user.save() callback without the password field.

    使用案例:应用程序用户从客户端更新其配置文件信息/设置(密码,联系信息,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's toObject() method,
              * then create a new object without the password property...
              * easiest way is lodash's _.omit function if you're using lodash 
              */
    
             var sanitizedUser = _.omit(user.toObject(), 'password');
             return res.status(201).send(sanitizedUser);
        });
    });
    
  • 2

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

  • 0

    在使用 password: { type: String, select: false } 时,您应该记住,当我们需要密码进行身份验证时,它也会排除密码 . 所以要随时准备好处理它 .

  • 14

    我在REST JSON响应中用于隐藏密码字段

    UserSchema.methods.toJSON = function() {
     var obj = this.toObject();
     delete obj.password;
     return obj;
    }
    
    module.exports = mongoose.model('User', UserSchema);
    

相关问题