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

Lui*_*ndo 74 mongoose mongodb node.js express

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

Blogs.findOne({...}).populate("user").exec()
Run Code Online (Sandbox Code Playgroud)

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

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

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

Joh*_*yHK 248

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

password: { type: String, select: false }
Run Code Online (Sandbox Code Playgroud)

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

Users.findOne({_id: id}).select('+password').exec(...);
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法将这个应用于传递给save()回调的对象?这样当我保存用户配置文件时,密码不包含在回调参数中. (7认同)
  • 在我看来,这是迄今为止最好的答案。添加一次,它是排除。比向每个查询添加选择或排除选项要好得多。 (4认同)
  • 大.你能提供一个关于在find中添加它的人的例子吗?假设我有:Users.find({id:_id})我应该在哪里添加"+密码+? (3认同)
  • 这应该是最终的答案。添加到架构中,并且不必忘记在查询期间进行排除。 (2认同)
  • 这是最灵活的解决方案! (2认同)

aar*_*ann 59

.populate('user' , '-password')
Run Code Online (Sandbox Code Playgroud)

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

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

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


Lui*_*ndo 19

编辑:

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

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

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

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


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

两者的一个例子:

包含总是但有时排除的例子:

Users.find().select("-password")
Run Code Online (Sandbox Code Playgroud)

要么

Users.find().exclude("password")
Run Code Online (Sandbox Code Playgroud)

exlucde总是包括有时例子:

Users.find().select("+password")
Run Code Online (Sandbox Code Playgroud)

但您必须在架构中定义:

password: { type: String, select: false }
Run Code Online (Sandbox Code Playgroud)

  • 这适用于我的本地策略:await User.findOne({ email: username }, { password: 1 }, async (err, user) => { ... }); (2认同)

Yll*_*shi 10

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

  • 会的,您可以使用 const query = model.findOne({ username }).select("+password");` 并在登录和密码更改/重置路由上使用它,否则确保它永远不会出现。到目前为止,默认情况下不返回它会更安全,因为我认为人们会犯错误 (3认同)

小智 8

const userSchema = new mongoose.Schema(
  {
    email: {
      type: String,
      required: true,
    },
    password: {
      type: String,
      required: true,
    },
  },
  {
    toJSON: {
      transform(doc, ret) {
        delete ret.password;
        delete ret.__v;
      },
    },
  }
);
Run Code Online (Sandbox Code Playgroud)


Ikb*_*bel 7

您可以使用模式来实现,例如:

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
Run Code Online (Sandbox Code Playgroud)

  • 我已经测试了所有答案,如果您正在开发api,我认为这是最佳选择。 (2认同)
  • 对我来说最好的选择,这种方法与我的身份验证方法不冲突 (2认同)

Ger*_*ere 6

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

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

module.exports = mongoose.model('User', UserSchema);
Run Code Online (Sandbox Code Playgroud)


Ner*_*Jok 6

我找到了另一种方法,通过向架构配置添加一些设置。

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 });
Run Code Online (Sandbox Code Playgroud)

通过向 toJSON 对象添加转换函数来排除字段名称。正如文档中所述

我们可能需要根据某些条件对结果对象执行转换,例如删除一些敏感信息或返回自定义对象。在本例中我们设置了可选transform功能。