比较密码 BcryptJS

Posted

技术标签:

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

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

步骤:

创建用户:

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

登录

    通过请求电子邮件值查找用户 如果找到比较密码 密码好发送 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
  
);

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

【问题讨论】:

【参考方案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" )
                
               )

【讨论】:

以上是关于比较密码 BcryptJS的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose 比较 BCRYPT 密码未填写

如何将密码文本与 bcrypt 哈希值进行比较?

比较(密码)属性

如何将字符串密码与 laravel 加密密码进行比较

使用 md5 将密码保存和比较到数据库作为二进制文件

比较来自不同网络服务器的散列​​密码