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

时间:2022-04-04 21:01:12

Suppose I have two collections/schemas. One is the Users Schema with username and password fields, then, I have a Blogs Schema that has a reference to the Users Schema in the author field. If I use Mongoose to do something like

假设我有两个集合/模式。一个是具有用户名和密码字段的用户模式,然后,我有一个blog模式,它引用author字段中的用户模式。如果我用猫鼬来做类似的事情。

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

I will have the Blog document and the user populated too, but how do I prevent Mongoose/MongoDB from returning the password field? The password field is hashed but it shouldn't be returned.

我将有博客文档和用户填充,但是如何防止Mongoose/MongoDB返回密码字段?密码字段被散列,但是不应该返回它。

I know I can omit the password field and return the rest of the fields in a simple query, but how do I do that with populate. Also, is there any elegant way to do this?

我知道我可以省略password字段并返回一个简单查询中的其余字段,但是如何使用populate来执行呢?还有,有什么优雅的方法吗?

Also, in some situations I do need to get the password field, like when the user wants to login or change the password.

此外,在某些情况下,我确实需要获取密码字段,比如当用户希望登录或更改密码时。

8 个解决方案

#1


42  

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

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

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

JohnnyHKs answer using Schema options is probably the way to go here.

使用模式选项的JohnnyHKs可能会选择这里。

Also note that query.exclude() only exists in the 2.x branch.

还要注意,query. exclusion()只存在于2中。x分支。

#2


166  

You can change the default behavior at the schema definition level using the select attribute of the field:

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

password: { type: String, select: false }

Then you can pull it in as needed in find and populate calls via field selection as '+password'. For example:

然后,您可以根据需要在find和调用中使用'+password'填充它。例如:

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

#3


11  

Edit:

编辑:

After trying both approaches, I found that the exclude always approach wasn't working for me for some reason using passport-local strategy, don't really know why.

在尝试了这两种方法之后,我发现排除方法在我使用passport-local策略时并不适合我,我也不知道为什么。

So, this is what I ended up using:

这就是我最后使用的

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

There's nothing wrong with the exclude always approach, it just didn't work with passport for some reason, my tests told me that in fact the password was being excluded / included when I wanted. The only problem with the include always approach is that I basically need to go through every call I do to the database and exclude the password which is a lot of work.

排除总是方法没有什么问题,只是因为某些原因它不能使用passport,我的测试告诉我,实际上密码在我想要的时候被排除/包含了。include always方法的唯一问题是,我基本上需要对数据库执行每次调用,并排除密码,这需要做很多工作。


After a couple of great answers I found out there are two ways of doing this, the "always include and exclude sometimes" and the "always exclude and include sometimes"?

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

An example of both:

的一个例子:

The include always but exclude sometimes example:

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

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

or

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

The exlucde always but include sometimes example:

但有时也包括例子:

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

but you must define in the schema:

但是您必须在模式中定义:

password: { type: String, select: false }

#4


3  

Assuming your password field is "password" you can just do:

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

.exclude('password')

There is a more extensive example here

这里有一个更广泛的例子

That is focused on comments, but it's the same principle in play.

它关注的是评论,但这是同样的原则。

This is the same as using a projection in the query in MongoDB and passing {"password" : 0} in the projection field. See here

这与在MongoDB中使用查询中的投影并在投影字段中传递{“password”:0}是一样的。在这里看到的

#5


3  

User.find().select('-password') is the right answer. You can not add select: false on the Schema since it will not work, if you want to login.

User.find().select('-password')是正确的答案。您不能在模式上添加select: false,因为如果您想登录的话,它将不起作用。

#6


0  

This is more a corollary to the original question, but this was the question I came across trying to solve my problem...

这更多的是对最初问题的推论,但这是我在试图解决我的问题时遇到的问题……

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

也就是说,如何将用户发送回user.save()回调中的客户端,而不使用密码字段。

Use case: application user updates their profile information/settings from the client (password, contact info, whatevs). You want to send the updated user information back to the client in the response, once it has successfully saved to mongoDB.

用例:应用程序用户从客户端更新他们的配置文件信息/设置(密码、联系信息、等等)。您希望在响应中将更新后的用户信息发送回客户机,一旦客户机成功保存到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);
    });
});

#7


0  

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

博客。findOne({ _id:id },{“密码”:0 }).populate(“用户”).exec()

#8


0  

You can achieve that using the schema, for example:

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

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

#1


42  

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

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

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

JohnnyHKs answer using Schema options is probably the way to go here.

使用模式选项的JohnnyHKs可能会选择这里。

Also note that query.exclude() only exists in the 2.x branch.

还要注意,query. exclusion()只存在于2中。x分支。

#2


166  

You can change the default behavior at the schema definition level using the select attribute of the field:

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

password: { type: String, select: false }

Then you can pull it in as needed in find and populate calls via field selection as '+password'. For example:

然后,您可以根据需要在find和调用中使用'+password'填充它。例如:

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

#3


11  

Edit:

编辑:

After trying both approaches, I found that the exclude always approach wasn't working for me for some reason using passport-local strategy, don't really know why.

在尝试了这两种方法之后,我发现排除方法在我使用passport-local策略时并不适合我,我也不知道为什么。

So, this is what I ended up using:

这就是我最后使用的

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

There's nothing wrong with the exclude always approach, it just didn't work with passport for some reason, my tests told me that in fact the password was being excluded / included when I wanted. The only problem with the include always approach is that I basically need to go through every call I do to the database and exclude the password which is a lot of work.

排除总是方法没有什么问题,只是因为某些原因它不能使用passport,我的测试告诉我,实际上密码在我想要的时候被排除/包含了。include always方法的唯一问题是,我基本上需要对数据库执行每次调用,并排除密码,这需要做很多工作。


After a couple of great answers I found out there are two ways of doing this, the "always include and exclude sometimes" and the "always exclude and include sometimes"?

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

An example of both:

的一个例子:

The include always but exclude sometimes example:

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

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

or

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

The exlucde always but include sometimes example:

但有时也包括例子:

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

but you must define in the schema:

但是您必须在模式中定义:

password: { type: String, select: false }

#4


3  

Assuming your password field is "password" you can just do:

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

.exclude('password')

There is a more extensive example here

这里有一个更广泛的例子

That is focused on comments, but it's the same principle in play.

它关注的是评论,但这是同样的原则。

This is the same as using a projection in the query in MongoDB and passing {"password" : 0} in the projection field. See here

这与在MongoDB中使用查询中的投影并在投影字段中传递{“password”:0}是一样的。在这里看到的

#5


3  

User.find().select('-password') is the right answer. You can not add select: false on the Schema since it will not work, if you want to login.

User.find().select('-password')是正确的答案。您不能在模式上添加select: false,因为如果您想登录的话,它将不起作用。

#6


0  

This is more a corollary to the original question, but this was the question I came across trying to solve my problem...

这更多的是对最初问题的推论,但这是我在试图解决我的问题时遇到的问题……

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

也就是说,如何将用户发送回user.save()回调中的客户端,而不使用密码字段。

Use case: application user updates their profile information/settings from the client (password, contact info, whatevs). You want to send the updated user information back to the client in the response, once it has successfully saved to mongoDB.

用例:应用程序用户从客户端更新他们的配置文件信息/设置(密码、联系信息、等等)。您希望在响应中将更新后的用户信息发送回客户机,一旦客户机成功保存到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);
    });
});

#7


0  

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

博客。findOne({ _id:id },{“密码”:0 }).populate(“用户”).exec()

#8


0  

You can achieve that using the schema, for example:

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

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