Załóżmy, że mam dwie kolekcje / schematy. Jednym z nich jest schemat użytkowników z polami nazwy użytkownika i hasła, a zatem mam schemat blogów, który zawiera odniesienie do schematu użytkowników w polu autora. Jeśli użyję Mongoose do zrobienia czegoś takiego
Blogs.findOne({...}).populate("user").exec()
Będę mieć również wypełniony dokument Blog i nazwę użytkownika, ale jak zapobiec zwracaniu pola hasła przez Mongoose / MongoDB? Pole hasła jest zaszyfrowane, ale nie powinno być zwracane.
Wiem, że mogę pominąć pole hasła i zwrócić pozostałe pola w prostym zapytaniu, ale jak to zrobić z wypełnieniem. Czy jest na to jakiś elegancki sposób?
Ponadto w niektórych sytuacjach potrzebuję pola hasła, na przykład gdy użytkownik chce się zalogować lub zmienić hasło.
Odpowiedzi:
.populate('user' , '-password')
http://mongoosejs.com/docs/populate.html
Odpowiedź JohnnyHKs za pomocą opcji schematu jest prawdopodobnie sposobem na przejście tutaj.
Należy również pamiętać, że
query.exclude()
istnieje tylko w gałęzi 2.x.źródło
Możesz zmienić domyślne zachowanie na poziomie definicji schematu za pomocą
select
atrybutu pola:password: { type: String, select: false }
Następnie możesz pobrać go w razie potrzeby
find
ipopulate
wywołać przez wybór pola jako'+password'
. Na przykład:Users.findOne({_id: id}).select('+password').exec(...);
źródło
Edytować:
Po wypróbowaniu obu podejść stwierdziłem, że metoda wykluczania zawsze nie działa dla mnie z jakiegoś powodu przy użyciu strategii lokalnej paszportowej, naprawdę nie wiem dlaczego.
Oto, co ostatecznie użyłem:
Blogs.findOne({_id: id}) .populate("user", "-password -someOtherField -AnotherField") .populate("comments.items.user") .exec(function(error, result) { if(error) handleError(error); callback(error, result); });
Nie ma nic złego w podejściu wykluczaj zawsze, po prostu z jakiegoś powodu nie działało z paszportem, moje testy wykazały, że w rzeczywistości hasło zostało wykluczone / uwzględnione, kiedy chciałem. Jedynym problemem związanym z podejściem włączającym zawsze jest to, że w zasadzie muszę przejść przez każde wywołanie bazy danych i wykluczyć hasło, co jest dużo pracy.
Po kilku świetnych odpowiedziach odkryłem, że można to zrobić na dwa sposoby: „zawsze dołączaj i wykluczaj czasami” oraz „zawsze wykluczaj i dołączaj czasami”?
Przykład obu:
Uwzględnij zawsze, ale czasami wykluczaj przykład:
Users.find().select("-password")
lub
Users.find().exclude("password")
Exlucde zawsze, ale czasami zawiera przykład:
Users.find().select("+password")
ale musisz zdefiniować w schemacie:
password: { type: String, select: false }
źródło
.select("+field")
to przynosi tylko__id
, choć.select("-field")
ładnie wyklucza pole, które chcęselect: false
jest to obowiązkoweUser.find().select('-password')
to właściwa odpowiedź. Nie możesz dodaćselect: false
schematu, ponieważ nie zadziała, jeśli chcesz się zalogować.źródło
const query = model.findOne({ username }).select("+password");
i używać do zmiany / resetowania tras logowania i hasła, a także upewnij się, że nigdy nie wyjdzie. Jest to o wiele bezpieczniejsze, aby nie wracało domyślnie, ponieważ ludziom udowodniono błędy imoMożesz to osiągnąć za pomocą schematu, na przykład:
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
źródło
Używam do ukrywania pola hasła w mojej odpowiedzi 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);
źródło
Zakładając, że Twoje hasło to „hasło”, możesz po prostu:
.exclude('password')
Jest bardziej rozległe przykład tutaj
Skupia się na komentarzach, ale ta sama zasada obowiązuje w grze.
Jest to to samo, co użycie projekcji w kwerendzie w MongoDB i przekazanie
{"password" : 0}
w polu projekcji. Zobacz tutajźródło
Blogs.findOne({ _id: id }, { "password": 0 }).populate("user").exec()
źródło
Rozwiązaniem jest, aby nigdy nie przechowywać haseł w postaci zwykłego tekstu. Powinieneś użyć pakietu takiego jak bcrypt lub password-hash .
Przykładowe użycie haszowania hasła:
var passwordHash = require('password-hash'); var hashedPassword = passwordHash.generate('password123'); console.log(hashedPassword); // sha1$3I7HRwy7$cbfdac6008f9cab4083784cbd1874f76618d2a97
Przykładowe użycie do weryfikacji hasła:
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
źródło
Obiekt DocumentToObjectOptions można przekazać do schema.toJSON () lub schema.toObject () .
Zobacz definicję TypeScript z @ 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 ma opcję transformacji, która uruchamia niestandardową funkcję po przekonwertowaniu dokumentu na obiekt javascript. Tutaj możesz ukryć lub zmodyfikować właściwości, aby spełnić swoje potrzeby.
Więc powiedzmy, że używasz schema.toObject () i chcesz ukryć ścieżkę do hasła ze schematu użytkownika. Powinieneś skonfigurować ogólną funkcję transformacji, która będzie wykonywana po każdym wywołaniu toObject ().
UserSchema.set('toObject', { transform: (doc, ret, opt) => { delete ret.password; return ret; } });
źródło
Znalazłem inny sposób, aby to zrobić, dodając pewne ustawienia do konfiguracji schematu.
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 });
Dodając funkcję transformacji do obiektu toJSON z nazwą pola do wykluczenia. jak w dokumentach stwierdzono :
źródło
router.get('/users',auth,(req,res)=>{ User.findById(req.user.id) //skip password .select('-password') .then(user => { res.json(user) }) })
źródło
Podczas korzystania
password: { type: String, select: false }
należy pamiętać, że spowoduje to również wykluczenie hasła, gdy będziemy go potrzebować do uwierzytelnienia. Przygotuj się więc na obsługę tego, jak chcesz.źródło
Jest to bardziej konsekwencja pierwotnego pytania, ale było to pytanie, na które natknąłem się, próbując rozwiązać mój problem ...
Mianowicie, jak odesłać użytkownika z powrotem do klienta w wywołaniu zwrotnym user.save () bez pola hasła.
Przykład zastosowania: użytkownik aplikacji aktualizuje swoje dane profilowe / ustawienia z klienta (hasło, dane kontaktowe, cokolwiek). Chcesz wysłać zaktualizowane informacje o użytkowniku z powrotem do klienta w odpowiedzi, po pomyślnym zapisaniu ich w 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); }); });
źródło
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; }, }, } );
źródło