【问题标题】:Compare passwords BcryptJS比较密码 BcryptJS
【发布时间】:2017-02-25 20:41:02
【问题描述】:

所以我正在尝试构建一个非常基本的用户登录。我正在尝试创建一个用户,然后使用这些凭据登录并取回 JSON Web 令牌。我被困的地方是尝试比较密码然后发送响应。

步骤:

创建用户:

  1. 输入邮箱和密码
  2. 盐/哈希用户密码
  3. 将用户存入数据库
  4. 返回成功

登录

  1. 通过请求电子邮件值查找用户
  2. 如果找到比较密码
  3. 密码好发送 JSON Web Token

用户模型

email:{ 
  type: String,
  required: true,
  unique: true
},
password: {
  type: String,
  required: true
}

用户路线

var express     = require('express');
var router      = express.Router();
var jwt         = require('jsonwebtoken');
var bcrypt      = require('bcryptjs');

// Create User
...
bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash("superSecret", salt, function(err, hash) {
      user.password = hash;
      user.save();
      res.json({success: true, message: 'Create user successful'});
    });
  });
...

// Login
...
bcrypt.compare(req.body.password, 'superSecret', function(err, res) {
  if(req.body.password != user.password){
    res.json({success: false, message: 'passwords do not match'});
  } else {
    // Send JWT
  }
});

所以这里的两个问题是,我无法发送响应,也无法比较密码。完全坚持这一点,任何帮助将不胜感激。

【问题讨论】:

    标签: javascript node.js express bcrypt


    【解决方案1】:

    doc 中所述,您应该像这样使用bcrypt.compare

    bcrypt.compare(req.body.password, user.password, function(err, res) {
      if (err){
        // handle error
      }
      if (res)
        // Send JWT
      } else {
        // response is OutgoingMessage object that server response http request
        return response.json({success: false, message: 'passwords do not match'});
      }
    });
    

    这是一篇关于Password Authentication with Mongoose (Part 1): bcrypt的好帖子

    【讨论】:

    • 那是我之前参考过的一篇文章,一开始没有注册,不过再看看吧。另一个问题是在 compare 方法中运行 res.[send][json] 将导致 unresolved method or function error。所以解决这个问题的唯一方法似乎是设置某种类型的回调View Gist
    • 变量名冲突的问题,res.json应该是response.json,其中response指的是OutgoingMessage。我已经更新了答案,请检查一下。
    【解决方案2】:

    如果我们在浏览器(HTML)中使用 bcryptjs,那么您可以添加 bcryptjs CDN 来执行此操作。

    CDN - https://cdn.jsdelivr.net/npm/bcryptjs@2.4.3/dist/bcrypt.js

    示例-

    HTML-(在标签中添加上面的CDN)

    JS-

        var bcrypt = dcodeIO.bcrypt;
    
        /** One way, can't decrypt but can compare */
        var salt = bcrypt.genSaltSync(10);
    
        /** Encrypt password */
        bcrypt.hash('anypassword', salt, (err, res) => {
            console.log('hash', res)
            hash = res
            compare(hash)
        });
    
        /** Compare stored password with new encrypted password */
        function compare(encrypted) {
            bcrypt.compare('aboveusedpassword', encrypted, (err, res) => {
                // res == true or res == false
                console.log('Compared result', res, hash) 
            })
        }
    

    如果你想在 Nodejs 中做同样的事情

    /** 像下面这样导入 lib 并使用与上面写的相同的功能 */

        var bcrypt = require('bcryptjs')
    

    【讨论】:

    • 鲍勃是你的叔叔。 2021年有效
    【解决方案3】:
    //required files
    const express = require('express')
    const router = express.Router();
    
    //bcryptjs
    const bcrypt = require('bcryptjs')
    
    //User modal of mongoDB
    const User = require('../../models/User')
    
    
    //Post request for login
    router.post('/', (req, res) => {
        //email and password
        const email = req.body.email
        const password = req.body.password
    
        //find user exist or not
        User.findOne({ email })
            .then(user => {
                //if user not exist than return status 400
                if (!user) return res.status(400).json({ msg: "User not exist" })
    
                //if user exist than compare password
                //password comes from the user
                //user.password comes from the database
                bcrypt.compare(password, user.password, (err, data) => {
                    //if error than throw error
                    if (err) throw err
    
                    //if both match than you can do anything
                    if (data) {
                        return res.status(200).json({ msg: "Login success" })
                    } else {
                        return res.status(401).json({ msg: "Invalid credencial" })
                    }
    
                })
    
            })
    
    })
    
    module.exports = router
    

    【讨论】:

      【解决方案4】:

      据我所知,您的逻辑是正确的。

      如果您使用的是猫鼬,我建议您使用 pre 'save' 钩子。

      用户架构

      userSchema.pre('save', function(next) {
        // only hash the password if it has been modified (or is new)
        if (!this.isModified('password')) {
          return next();
        }
        // generate a salt
        return bcrypt.genSalt(10, function(error, salt) {
          if (error) {
            return next(error);
          }
      
        // hash the password using the new salt
          return bcrypt.hash(this.password, salt, function(error, hash) {
            if (error) {
              return next(error);
            }
            // override the cleartext password with the hashed one
            this.password = hash;
            return next();
          });
        });
      });
      
      
      userSchema.methods.comparePassword = function(passw, cb) {
        bcrypt.compare(passw, this.password, function(err, isMatch) {
          if (err) {
            return cb(err, false);
          }
          return cb(null, isMatch);
        });
      };
      

      在你的路线中:

      登录

      ...
      return user.comparePassword(password, function(error, isMatch) {
        var payload = {
        iat: Math.round(Date.now() / 1000),
        exp: Math.round((Date.now() / 1000) + 30 * 24 * 60),
        iss: 'Whatever the issuer is example: localhost:3000',
        email: user.email
        };
      
        var token = jwt.encode(payload, 'secret');
        if (isMatch && !error) {
          // if user is found and password is right create a token
          return res.json({
            success: true,
            token: `JWT ${token}`,
            user: user,
            msg: 'Authentication was succesful'
            });
          }
          return next({code: 401, msg: 'Password is incorrect'});
        });
      });
      

      创建用户

      // Pre hook will take care of password creation
      return user.save()
      .then(function(user) {
        var payload = {
        iat: Math.round(Date.now() / 1000),
        exp: Math.round((Date.now() / 1000) + 30 * 24 * 60),
        iss: 'Whatever the issuer is example: localhost:3000',
        email: user.email
        };
      
        var token = jwt.encode(payload, 'secret');
        return res.status(201).json({user, token: `JWT ${token}`, msg: 'User was succesfully created'});
      })
      .catch((err) => next(err));
      

      【讨论】:

      • 所以我采纳了您的建议并逐个分解。但是,看起来user is undefined 在调用User.save()... 时正在发生,这与“预钩子”有关。我已经添加了这两个要点,因此维护路线和模型会更容易一些。再次感谢您的帮助user modeluser route
      • 所以我更新了 2 Gist,用户对象现在正在传递到预保存钩子中,但是 this.password 是未定义的。我试过user.password 但也无济于事
      • 看起来return bcrypt.genSalt(10, function(error, salt) { 是无法调用this 的地方
      • 所以密码现在正在被散列,但回调永远不会返回到路由。 return bcrypt.hash(){ ... newUser.password = hash; return next(); // everything stops here, callback never happens ... }
      【解决方案5】:
      bcrypt.compare(req.body.password, user.password, function(err, results){
                      if(err){
                          throw new Error(err)
                       }
                       if (results) {
                          return res.status(200).json({ msg: "Login success" })
                      } else {
                          return res.status(401).json({ msg: "Invalid credencial" })
                      }
                     })
      

      【讨论】:

        猜你喜欢
        • 2017-02-25
        • 2020-12-04
        • 2020-05-24
        • 2013-05-26
        • 2017-10-31
        • 2021-04-10
        • 2019-09-27
        • 2010-10-04
        • 1970-01-01
        相关资源
        最近更新 更多