Javascript bcrypt密码与比较方法的比较结果总是错误的

Javascript bcrypt密码与比较方法的比较结果总是错误的,javascript,mongodb,express,bcrypt,mongoose-schema,Javascript,Mongodb,Express,Bcrypt,Mongoose Schema,首先,我知道同样的问题在我之前被问过很多次,但我在StackOverflow上发现的任何问题都找不到答案 我最近刚开始学习express,第一次尝试用 javascript库(来自PHPworld)。我已经声明了一个MongoDB模型模式,其中包含一些准备工作和一个将输入的密码与 数据库中存储的哈希密码。除了comparePassword方法从未返回匹配的密码外,其他一切似乎都正常工作 我使用bcryptjs库进行密码散列和比较,使用passport库进行身份验证 用户模型(models/Use

首先,我知道同样的问题在我之前被问过很多次,但我在StackOverflow上发现的任何问题都找不到答案

我最近刚开始学习
express
,第一次尝试用 javascript库(来自
PHP
world)。我已经声明了一个
MongoDB
模型模式,其中包含一些准备工作和一个将输入的密码与 数据库中存储的哈希密码。除了
comparePassword
方法从未返回匹配的密码外,其他一切似乎都正常工作

我使用
bcryptjs
库进行密码散列和比较,使用
passport
库进行身份验证

用户模型(models/User.js):

身份验证策略(config/passport.js):

最后是我的登录路径(routes/auth.js):

编辑:

如果我删除控制台.log中的
输出:

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);
        });
    };
并尝试执行回调函数,我将得到以下错误:

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)
编辑2:

因此,我终于能够比较密码,并且能够
console.log
密码是否匹配。我能够通过承诺实现这一点。现在我不确定如何将该承诺传递给
passport
处理程序,以便它能够返回路由的用户结果

以下是
comparePassword
方法:

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);
        });
    });
};
以及
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);
            })
        });
    }
));

我以为你只是在bcrypt比较中传递回调。确保将明文密码作为参数传递,并将其与db中的哈希密码进行比较

而不是这样做

 if (!user.comparePassword(password)) { 
     return done(null, false, {
         error: true,
                message: 'Incorrect creditentials'
     });
 }
为什么不这样做呢

user.comparePassword(function (err, match) {
     if (err) throw err;
     if (!match) {
         return done(null, false, {
              error: true,
              message: 'Incorrect creditentials'
         });
     } else {
         // Password match
     }
});
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');
});
在bcrypt compare方法中,更改回调参数,err必须是第一个,res必须是第二个

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);
    });
};
编辑

当密码匹配并传递用户对象时,需要调用done

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);
            })
        });
    }
));
在中档软件中

我猜你的路线是这样的

user.comparePassword(function (err, match) {
     if (err) throw err;
     if (!match) {
         return done(null, false, {
              error: true,
              message: 'Incorrect creditentials'
         });
     } else {
         // Password match
     }
});
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');
});

我以为你只是在bcrypt比较中传递回调。确保将明文密码作为参数传递,并将其与db中的哈希密码进行比较

而不是这样做

 if (!user.comparePassword(password)) { 
     return done(null, false, {
         error: true,
                message: 'Incorrect creditentials'
     });
 }
为什么不这样做呢

user.comparePassword(function (err, match) {
     if (err) throw err;
     if (!match) {
         return done(null, false, {
              error: true,
              message: 'Incorrect creditentials'
         });
     } else {
         // Password match
     }
});
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');
});
在bcrypt compare方法中,更改回调参数,err必须是第一个,res必须是第二个

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);
    });
};
编辑

当密码匹配并传递用户对象时,需要调用done

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);
            })
        });
    }
));
在中档软件中

我猜你的路线是这样的

user.comparePassword(function (err, match) {
     if (err) throw err;
     if (!match) {
         return done(null, false, {
              error: true,
              message: 'Incorrect creditentials'
         });
     } else {
         // Password match
     }
});
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');
});

我尝试了这个方法,但行为仍然与我的原始代码相同:如果我尝试控制台匹配,它将输出
“密码不匹配”
,如果我删除
返回
并尝试回调,我会得到一个错误:
cb(null,isMatch);类型错误:未定义不是函数
Oh。我只是注意到您将return放在console.log之后。什么意思?是否要防止该错误。您不能像那样使用等价字符串直接比较它,它将不起作用。让bcrypt.compare处理它,然后尝试console.log(isMatch),这是您将得到的结果。该错误意味着cb未被识别为函数。您需要传递回调函数,正如我在上面的回答中所说的。请您再告诉我一点好吗?我对Javascript比较陌生,因为我主要使用PHP和类似的服务器端语言编写代码,对那些回调、承诺等有点困惑。哦,我明白了。回调和承诺的创建实际上是为了处理asncyrous。因此,nodejs是一种异步的特性,那么您就不能同时使用这两种方法。您可以选择使用回调或承诺。有很多简单的文档解释了回调和承诺的细节。我尝试了这一点,但行为仍然与我的原始代码相同:如果我尝试控制台匹配,它将输出
“密码不匹配”
,如果我删除
返回
并尝试回调,我会得到一个错误:
cb(null,isMatch); 类型错误:未定义不是函数
Oh。我只是注意到您将return放在console.log之后。什么意思?是否要防止该错误。您不能像那样使用等价字符串直接比较它,它将不起作用。让bcrypt.compare处理它,然后尝试console.log(isMatch),这是您将得到的结果。该错误意味着cb未被识别为函数。您需要传递回调函数,正如我在上面的回答中所说的。请您再告诉我一点好吗?我对Javascript比较陌生,因为我主要使用PHP和类似的服务器端语言编写代码,对那些回调、承诺等有点困惑。哦,我明白了。回调和承诺的创建实际上是为了处理asncyrous。因此,nodejs是一种异步的特性,那么您就不能同时使用这两种方法。您可以选择使用回调或承诺。有很多简单的文档解释了回调和承诺的细节。