node.js 如何保护 Mongoose/MongoDB 中的密码字段,使其在填充集合时不会在查询中返回?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12096262/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to protect the password field in Mongoose/MongoDB so it won't return in a query when I populate collections?
提问by Luis Elizondo
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
假设我有两个集合/模式。一个是带有用户名和密码字段的用户架构,然后,我有一个博客架构,它在作者字段中引用了用户架构。如果我使用猫鼬做类似的事情
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.
我将同时填充博客文档和用户,但如何防止猫鼬/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?
我知道我可以省略密码字段并在一个简单的查询中返回其余的字段,但是我如何使用 populate 来做到这一点。另外,有没有什么优雅的方法来做到这一点?
Also, in some situations I do need to get the password field, like when the user wants to login or change the password.
此外,在某些情况下,我确实需要获取密码字段,例如用户想要登录或更改密码时。
采纳答案by aaronheckmann
.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 使用 Schema 选项回答可能是这里的方法。
Also note that query.exclude()only exists in the 2.x branch.
另请注意,query.exclude()仅存在于 2.x 分支中。
回答by JohnnyHK
You can change the default behavior at the schema definition level using the selectattribute of the field:
您可以使用select字段的属性在架构定义级别更改默认行为:
password: { type: String, select: false }
Then you can pull it in as needed in findand populatecalls via field selection as '+password'. For example:
然后,您可以根据需要将其拉入find并populate通过字段选择调用为'+password'。例如:
Users.findOne({_id: id}).select('+password').exec(...);
回答by Luis Elizondo
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.
在尝试了这两种方法后,我发现由于某种原因,使用本地护照策略,始终排除方法对我不起作用,我真的不知道为什么。
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.
exclude always 方法没有任何问题,它只是出于某种原因不能与护照一起使用,我的测试告诉我,实际上密码被排除/包含在我想要的时候。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 sometimesexample:
包括总是但有时排除示例:
Users.find().select("-password")
or
或者
Users.find().exclude("password")
The exlucde always but include sometimesexample:
排除总是但有时包括示例:
Users.find().select("+password")
but you must define in the schema:
但您必须在架构中定义:
password: { type: String, select: false }
回答by Ylli Gashi
User.find().select('-password')is the right answer. You can not add select: falseon the Schema since it will not work, if you want to login.
User.find().select('-password')是正确的答案。select: false如果您想登录,则无法添加架构,因为它不起作用。
回答by Ikbel
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
回答by Adam Comerford
Assuming your password field is "password" you can just do:
假设您的密码字段是“密码”,您可以这样做:
.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}投影字段相同。看这里
回答by Gere
I'm using for hiding password field in my REST JSON response
我用于在我的 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);
回答by netishix
You can pass a DocumentToObjectOptionsobject to schema.toJSON()or schema.toObject().
您可以将DocumentToObjectOptions对象传递给schema.toJSON()或schema.toObject()。
See TypeScript definition from @types/mongoose
请参阅@types/mongoose 中的TypeScript 定义
/**
* 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;
DocumentToObjectOptionshas a transform option that runs a custom function after converting the document to a javascript object. Here you can hide or modify properties to fill your needs.
DocumentToObjectOptions有一个转换选项,可在将文档转换为 javascript 对象后运行自定义函数。您可以在此处隐藏或修改属性以满足您的需求。
So, let's say you are using schema.toObject() and you want to hide the password path from your User schema. You should configure a general transform function that will be executed after every toObject() call.
因此,假设您正在使用 schema.toObject() 并且您想从您的用户架构中隐藏密码路径。您应该配置一个将在每次 toObject() 调用后执行的通用转换函数。
UserSchema.set('toObject', {
transform: (doc, ret, opt) => {
delete ret.password;
return ret;
}
});
回答by Desai Ramesh
router.get('/users',auth,(req,res)=>{
User.findById(req.user.id)
//skip password
.select('-password')
.then(user => {
res.json(user)
})
})
回答by Cameron Hudson
The solution is to never store plaintext passwords. You should use a package like bcryptor password-hash.
解决方案是永远不要存储明文密码。你应该使用像bcrypt或password-hash这样的包。
Example usage to hash the password:
散列密码的示例用法:
var passwordHash = require('password-hash');
var hashedPassword = passwordHash.generate('password123');
console.log(hashedPassword); // sha1I7HRwy7$cbfdac6008f9cab4083784cbd1874f76618d2a97
Example usage to verify the password:
验证密码的示例用法:
var passwordHash = require('./lib/password-hash');
var hashedPassword = 'sha1I7HRwy7$cbfdac6008f9cab4083784cbd1874f76618d2a97';
console.log(passwordHash.verify('password123', hashedPassword)); // true
console.log(passwordHash.verify('Password0', hashedPassword)); // false

