简体   繁体   中英

Nodejs bcrypt compare not working properly

I am building an app with nodes qraphQl using apollo and I am trying to do a login page, but after signing up and and i try to sign in, my bcrypt would always return false,

in my user model

import bcrypt from 'bcryptjs';

const user = (sequelize, DataTypes) => {
  const User = sequelize.define('user', {    
    id: {
      type: DataTypes.INTEGER,
      autoIncrement: true,
      unique: true,
      primaryKey: true,
      field: 'id'
    },
    fullname: DataTypes.STRING,
    username: {
      type: DataTypes.STRING,
      allowNull: false,
      validate: {
        notEmpty: true,
      },
    },
    email: {
      type: DataTypes.STRING,
      allowedNull: false,
      validate: {
        notEmpty: true,
        isEmail: true, 
      }
    },
    password: {
      type: DataTypes.STRING,
      allowedNull: false,
      validate: {
        notEmpty: true,
        len: [7, 42],
      },
    },
    role: { 
      type: DataTypes.ENUM,
      values: ['ADMIN', 'INSTRUCTOR', 'STUDENT'],
      defaultValue: 'STUDENT'
    }
  });

User.beforeCreate(async function(user) {
  user.password = await user.generatePasswordHash(user)
});

User.beforeSave(async function(user)  {
  user.password = await user.generatePasswordHash(user)
});

User.prototype.generatePasswordHash = async function(user) {
    const saltRounds = 10;
    return await bcrypt.hash(user.password, saltRounds)
};

  User.prototype.validatePassword = async function(password) {
    console.log(this.password)
    const theReturn = await bcrypt.compare(password, this.password)
    console.log(theReturn)
    return theReturn;
  };

  User.associate = models => {
    User.hasMany(models.Message, { onDelete: 'CASCADE' });
  };

  User.findByLogin = async login => {
    let user = await User.findOne({
      where: { username: login },
    });

    if (!user) {
      user = await User.findOne({
        where: { email: login },
      });
    }

    return user;
  };

  return User;
};

export default user;

And in my users resolver, here is the code

import { combineResolvers } from 'graphql-resolvers';
import Joi from 'joi'
import { isAuthenticated, isAdmin } from './authorization';
import {SignUp, SignIn} from '../functions/joi'
import {createToken} from '../functions/jwt'

export default {

  Mutation: {
    signUp: async (parent, { username, fullname, email, password, Rpassword}, { models, secret }) => {
      if(password !== Rpassword){
        return new Error('Password did not match')
      }
      var thejoi = { username, fullname, email, password }
      const checkUserEm = await models.User.find({ where: { email: email }})
      if (checkUserEm) {
          return new Error('Email address already Exist')
      }
      const checkUserUs = await models.User.find({ where: { username: username }})
      if (checkUserUs) {
          return new Error('Username already Exist')
      }

      await Joi.validate(thejoi, SignUp, {abortEarly:false})
      const user = await models.User.create({
        username, 
        fullname, 
        email,
        password,
        role:'STUDENT'
      });
      return { token: createToken(user) };
    },
    signIn: async (parent, { login, password }, { models, secret }, ) => {
      var varrh = { password }
      await Joi.validate(varrh, SignIn, {abortEarly:false})
      const user = await models.User.findByLogin(login);

      if (!user) {
        return new Error('No user found with this login credentials.');
      }

      const isValid = await user.validatePassword(password);
      if (!isValid) { 
        return new Error('Invalid password .');
      }

      return { token: createToken(user) };
    }
  },
  User: {
    messages: async (user, args, { models }) => {
      return await models.Message.findAll({
        where: {
          userId: user.id
        }
      });
    },
  },
}

when i tried to signup, it worked, it stored the hassed password in the database, but when i tried to signIn i got this error message

{
  "errors": [
    {
      "message": "Invalid password .",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "signIn"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "Error: Invalid password .",
            "    at signIn (C:\\Users\\De Stone Of David\\Desktop\\node projects\\vue\\cybersec\\server\\src\\resolvers\\user.js:65:16)"
          ]
        }
      }
    }
  ],
  "data": null
}

In the console i got this

Executing (default): INSERT INTO `users` (`id`,`fullname`,`username`,`email`,`password`,`role`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'nsalknlsa','stones4semper','Eloike95@gmail.com','$2a$10$eX8zvI7/EJv6N.2RzbBh9e.qKoJXtmDNDw22nAY6dixTi4btWCB6G','STUDENT','2019-02-17 09:51:44','2019-02-17 09:51:44');
Executing (default): SELECT `id`, `fullname`, `username`, `email`, `password`, `role`, `createdAt`, `updatedAt` FROM `users` AS `user` WHERE `user`.`username` = 'Eloike95@gmail.com' LIMIT 1;
Executing (default): SELECT `id`, `fullname`, `username`, `email`, `password`, `role`, `createdAt`, `updatedAt` FROM `users` AS `user` WHERE `user`.`email` = 'Eloike95@gmail.com' LIMIT 1;

$2a$10$eX8zvI7/EJv6N.2RzbBh9e.qKoJXtmDNDw22nAY6dixTi4btWCB6G
false

Please I am really confused because its suppose to work, i have searched google but it didn't help me, how can i solve this issue? Thanks in advance.

OK so I faced the same problem and the solution is this.

In your user model file line :- const theReturn = await bcrypt.compare(password, this.password)

here password has already hashed the thing with compare or compareSync is that the first parameter should be the unhashed password that you enter in the login form.

The second parameter is an already hashed password that you want to compare your data with.

So all you have to do is not hash the password, because you are already hashing it and then sending it into the compare function it gets hashed twice. So you get an invalid password.

FYI, compare is used and required to handle the Promise; and compareSync is used, without a Promise. Also, compareSync returns a boolean value.

Hope that helps, thanks!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM