2017-01-15 1 views
1

Erstens weiß ich, dass die gleiche Frage schon oft vor mir gestellt wurde, aber ich konnte keine Antwort in einer dieser Fragen finden, die ich auf StackOverflow gefunden.bcrypt Passwort im Vergleich zu vergleichen Methode führt immer mit Fehler

Ich begann erst vor kurzem express und zum ersten Mal lernen, ich versuche Anwendung, sowohl, Backend und Frontend mit JavaScript-Bibliotheken (die sich aus PHP Welt) zu erstellen. Ich habe ein MongoDB Modell-Schema mit einigen Vorarbeiten und eine Funktion, die das eingegebene Passwort zu einem Hash-Passwort in der Datenbank gespeichert erklärt. Alles andere scheint gut zu funktionieren, außer dass die Methode comparePassword niemals ein passendes Passwort zurückgibt.

Ich benutze eine bcryptjs Bibliothek für Passwort Hashing und Vergleich und eine passport Bibliothek für die Authentifizierung.

User-Modell(Modelle/user.js):

var mongoose   = require('mongoose'), 
    Schema    = mongoose.Schema, 
    bcrypt    = require('bcryptjs'); 
    SALT_WORK_FACTOR = 10; 

var userSchema = new Schema({ 
    //id: ObjectId, 
    email: { 
     type: String, 
     unique: true, 
     required: true 
    }, 
    name: { 
     type: String, 
     required: true 
    }, 
    password: { 
     type: String, 
     required: true 
    } 
}); 

userSchema.pre('save', function(next) { // Hash the password before adding it to the database 
    var user = this; 

    // only hash the password if it has been modified (or is new) 
    if (!user.isModified('password')) return next(); 

    // generate a salt 
    bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) { 
     if (err) return next(err); 

     // hash the password using our new salt 
     bcrypt.hash(user.password, salt, function(err, hash) { 
      if (err) return next(err); 

      // override the cleartext password with the hashed one 
      user.password = hash; 
      next(); 
     }); 
    }); 
}); 

userSchema.methods.comparePassword = function(candidatePassword, cb) { 
    var user = this; 
    bcrypt.compare(candidatePassword, user.password, function(err, isMatch) { 
     console.log(candidatePassword); 
     console.log(user.password); 
     console.log((candidatePassword === user.password) ? 'passwords match' : 'passwords dont match'); 
     return; 
     if (err) return cb(null, err); 
      cb(null, isMatch); 
    }); 
}; 
module.exports = mongoose.model('User', userSchema); 

Strategie Authentication(config/passport.js):

var passport = require('passport'); 
var LocalStrategy = require('passport-local').Strategy; 
var mongoose = require('mongoose'); 
var User = mongoose.model('User'); 

passport.use(new LocalStrategy({ 
     usernameField: 'email' 
    }, 
    function(username, password, done) { 
     User.findOne({ email: username }, function (err, user) { 
      if (err) { return done(err); } 

      if (!user) { // Return if user not found in database 
       return done(null, false, { 
        message: 'User not found' 
       }); 
      } 

     // It will always output "Incorrect creditentials" 
      if (!user.comparePassword(password)) { 
       return done(null, false, { 
        error: true, 
        message: 'Incorrect creditentials' 
       }); 
      } 
      return done(null, user); // If credentials are correct, return the user object 
     }); 
    } 
)); 

Und schließlich, Meine Route zum Anmelden(routes/a uth.js):

var router = require('express').Router(); // get router instance 
var request = require('request'); 
var passport = require('passport'); 
var User = require('../../models/user'); 
var tokenAuth = require('../../middlewares/token'); 

router.post('/signin', function(req, res) { 
    passport.authenticate('local', function(err, user, info){ 
     var token; 

     if (err) { // If Passport throws/catches an error 
      res.status(404).json(err); 
      return; 
     } 

     if(user) { // If a user is found 
      token = user.generateJwt(); 
      res.status(200); 
      res.json({ 
       "token" : token 
      }); 
     } else { 
      // If user is not found 
      res.status(401).json(info); 
     } 
    })(req, res); 

}); 

module.exports = router; 

EDIT:

Wenn ich entfernen Sie die console.log Ausgabe in:

bcrypt.compare(candidatePassword, user.password, function(err, isMatch) { 
      console.log(candidatePassword); 
      console.log(user.password); 
      console.log((candidatePassword === user.password) ? 'passwords match' : 'passwords dont match'); 
      return; 
      if (err) return cb(null, err); 
       cb(null, isMatch); 
     }); 
    }; 

und versuchen, die Callback-Funktion auszuführen, werde ich die folgende Fehlermeldung erhalten :

cb(null, isMatch); 
     ^
TypeError: undefined is not a function 
    at D:\project\backend\dist\models\user.js:51:9 
    at D:\project\node_modules\bcryptjs\dist\bcrypt.js:297:21 
    at D:\project\node_modules\bcryptjs\dist\bcrypt.js:1250:21 
    at Object.next [as _onImmediate] (D:\project\node_modules\bcryptjs\dist\bcrypt.js:1130:21) 
    at processImmediate [as _immediateCallback] (timers.js:354:15) 

EDIT 2:

So konnte ich endlich die Passwörter vergleichen und konnte console.log ob die Passwörter übereinstimmen oder nicht. Mit Promises konnte ich das durchziehen. Jetzt bin ich mir nicht sicher, wie ich dieses Versprechen an den Handler passport weiterleiten kann, damit es die Benutzerergebnisse für die Routen zurückgeben kann.

Hier ist die comparePassword Methode:

userSchema.methods.comparePassword = function(candidatePassword) { 
    var user = this; 

    return new Promise(function(resolve,reject) 
    { 
     bcrypt.compare(candidatePassword, user.password, function (err, isMatch) { 
      // Prevent conflict btween err and isMatch 
      if (err) 
       reject(new Error("Error checking use password")); 
      else 
       console.log(isMatch === true ? 'passwords match' : 'passwords dont match'); 
       return; 
       resolve(isMatch); 
     }); 
    }); 
}; 

und die passport.js:

passport.use(new LocalStrategy({ 
     usernameField: 'email' 
    }, 
    function(username, password, done) { 
     User.findOne({ email: username }, function (err, user) { 
      if (err) { return done(err); } 
      // Return if user not found in database 
      user.comparePassword(password).then(function(isMatch) { 
       return isMatch === true ? user : null; // How to pass the user object to route?? 
      }).catch(function (err) { // handle possible errors 
       return done(err); 
      }) 
     }); 
    } 
)); 

Antwort

0

Vielleicht haben Sie gerade Rückruf vergleichen in bcrypt vorbei. Stellen Sie sicher, dass Sie plaintextpassword als Parameter übergeben und mit dem Hash-Passwort von db vergleichen.

Statt dies zu tun

if (!user.comparePassword(password)) { 
    return done(null, false, { 
     error: true, 
       message: 'Incorrect creditentials' 
    }); 
} 

Warum es nicht wie dieses

user.comparePassword(function (err, match) { 
    if (err) throw err; 
    if (!match) { 
     return done(null, false, { 
       error: true, 
       message: 'Incorrect creditentials' 
     }); 
    } else { 
     // Password match 
    } 
}); 

und in bcrypt vergleichen Methode, die Callback-param ändern, irren muss die erste und res sein müssen der zweite

userSchema.methods.comparePassword = function(candidatePassword, cb) { 
    var user = this; 
    bcrypt.compare(candidatePassword, user.password, function(err, isMatch) { 
     console.log(candidatePassword); 
     console.log(user.password); 
     // You shouldn't compare the password directly like this. Let the method handle it and once the response is return (isMatch), pass it as callback param. Comment this line, you don't need it 
     //console.log((candidatePassword === user.password) ? 'passwords match' : 'passwords dont match'); 
     //return; 
     // Prevent conflict btween err and isMatch 
     if (err) return cb(err, null); 
      cb(null, isMatch); 
    }); 
}; 

EDIT

benötigen Sie getan rufen, wenn Passwort Übereinstimmung vorhanden ist und übergeben Objekt Benutzer

passport.use(new LocalStrategy({ 
     usernameField: 'email' 
    }, 
    function(username, password, done) { 
     User.findOne({ email: username }, function (err, user) { 
      if (err) { return done(err); } 
      // Return if user not found in database 
      user.comparePassword(password).then(function(isMatch) { 
       if (isMatch) { 
        return done(null, user); 
       } else { 
        return done(null, false); 
       } 
      }).catch(function (err) { // handle possible errors 
       return done(err); 
      }) 
     }); 
    } 
)); 

In Strecke Middeware

Ich denke, Ihre Route so etwas wie dieses

ist
app.post('/login', 
    passport.authenticate('local', { 
    successRedirect: '/loginSuccess', 
    failureRedirect: '/loginFailure' 
    }) 
); 

app.get('/loginFailure', function(req, res, next) { 
    res.send('Failed to authenticate'); 
}); 

// Login success should return user object 
app.get('/loginSuccess', function(req, res, next) { 
    res.send('Successfully authenticated'); 
}); 
+0

ich dies versucht und das Verhalten ist immer noch das gleiche wie mit meinem ursprünglichen Code: Wenn ich versuche, die Übereinstimmung zu trösten, wird es ausgegeben "Passwörter stimmen nicht überein" und wenn ich die Rückkehr und entfernen versuche den Callback bekomme ich einen Fehler: 'cb (null, isMatch); TypeError: undefined ist keine Funktion –

+0

Oh. Ich merke gerade, dass Sie nach console.log eine Zeile in die Zeile setzen. Was ist der Punkt? Möchten Sie den Fehler verhindern? Sie können es nicht direkt vergleichen, indem Sie äquivalentString verwenden, es wird nicht funktionieren. Lassen Sie bcrypt.compare damit umgehen und versuchen Sie console.log (isMatch), was Sie bekommen werden. – digit

+0

Dieser Fehler bedeutet, dass cb nicht als eine Funktion erkannt wird. Sie müssen Callback-Funktion übergeben, wie ich in der obigen Antwort angegeben habe. – digit

Verwandte Themen