• 1401/10/08

هش پسورد با bcrypt :

سلام و درود

استاد امیدوارم حالتون خوب باشه
من به یه مشکلی در مورد متد hash  و compare برخوردم
از نظر خودم که ارور منطقی نیستش ولی حالا به هر حال بهش برخوردم
من بکند رو با nodejs و فرانت رو با reactjs برنامه نویسی کردم

من موقعی که کاربر ثبت نام میکنه پسوردش رو هش میکنم 

userSchema.pre("save", async function (next) {
  try {
    if (this.isModified("password")) {
      this.password = await hashPassword(this.password);
    }
    next();
  } catch (err) {
    next(err);
  }
});

و تا اینجا عادیه
وقتی لاگین هم میکنم کار میکنه

module.exports = async (req, res) => {
  const errors = [];

  try {
    const { username, password, rememberMe } = req.body;
    let user = await User.findOne({ username });
    if (user == null) {
      user = await User.findOne({ email: username });
      if (!user) {
        errors.push({
          name: "email",
          message: "کاربر با این نام کاربری یا ایمیل در سایت موجود نمیباشد!",
        });
        return res
          .status(400)
          .json({ status: "error", statusCode: 400, errors });
      }
    }
    console.log(typeof password)
    bcrypt.compare(password, user.password, (err, isMatch) => {
      if (err) {
        errors.push({
          name: "password",
          message: err.message,
        });
        return res
          .status(400)
          .json({ status: "error", statusCode: 400, errors });
      }
      if (isMatch) {
        let jwtSecretKey = process.env.JWT_SECRET_KEY;
        let data = {
          time: Date(),
          userId: user.id,
        };
        const token = jwt.sign(data, jwtSecretKey, {
          expiresIn: `${rememberMe ? "10d" : "2h"}`,
        });
        res.status(200).json({
          status: "success",
          statusCode: 200,
          errors: null,
          user: { ...user._doc, token, password: undefined },
        });
      } else {
        errors.push({
          name: "password",
          message: "نام کاربری/ایمیل یا کلمه عبور اشتباه است!",
        });
        return res
          .status(400)
          .json({ status: "error", statusCode: 400, errors });
      }
    });
  } catch (err) {
    console.log(err);
    error.inner.forEach((e) => {
      errors.push({
        name: e.path,
        message: e.message,
      });
    });
    return res.status(400).json({ status: "error", statusCode: 400, errors });
  }
};

تا اینجا همه چی اکیه
من یه بخش دیگه هم برای تغییر کلمه عبور دارم که اونجا کلمه عبور قبلی و جدید رو از کاربر میگیرم

exports.changePassword = async (req, res) => {
  const errors = [];

  try {
    const jwtValidation = tokenValidation(req.headers["x-access-token"]);
    if (jwtValidation.userId !== null) {
      const user = await User.findById(jwtValidation.userId);
      if (user) {
        if (
          req.body.password &&
          req.body.newPassword &&
          req.body.newPasswordRepeat
        ) {
          if (req.body.newPassword == req.body.newPasswordRepeat) {
            console.log(typeof req.body.newPassword);
            const hashedPassword = await hashPassword(req.body.newPassword) //! Hash
            console.log("req.body.password", req.body);
            console.log("user.password", user.password);
            bcrypt.compare(req.body.password, user.password, (err, isMatch) => {
              if (err) {
                console.log(err);
                return res.status(400).json({
                  status: "error",
                  statusCode: 400,
                  errors: [
                    {
                      name: "bcrypt",
                      message: "خطایی از سمت سرور رخ داده است!",
                    },
                  ],
                });
              }
              if (isMatch) {
                if (hashedPassword) {
                  console.log("hashedPassword", hashedPassword);
                  user.password = hashedPassword;
                  user.save();
                  return res.status(200).json({
                    status: "success",
                    statusCode: 200,
                    errors: null,
                  });
                } else {
                  console.log(err);
                  return res.status(400).json({
                    status: "error",
                    statusCode: 400,
                    errors: [
                      {
                        name: "bcrypt",
                        message: "خطایی از سمت سرور رخ داده است!",
                      },
                    ],
                  });
                }
              } else {
                return res.status(400).json({
                  status: "error",
                  statusCode: 400,
                  errors: [
                    {
                      name: "password",
                      message: "کلمه عبور ارسالی با کلمه عبور اصلی یکسان نیست!",
                    },
                  ],
                });
              }
            });
          } else {
            return res.status(400).json({
              status: "error",
              statusCode: 400,
              errors: [
                {
                  name: "newPassword",
                  message: "کلمه عبور جدید و تکرار آن یکسان نیستند!",
                },
              ],
            });
          }
        }
      } else {
        return res.status(400).json({
          status: "error",
          statusCode: 400,
          errors: [{ name: "user", message: "کاربر مورد نظر یافت نشد!" }],
        });
      }
    } else {
      return res.status(400).json({
        status: "error",
        statusCode: 400,
        errors: jwtValidation.errors,
      });
    }
  } catch (err) {
    console.log(err);
    err.inner.forEach((e) => {
      errors.push({
        name: e.path,
        message: e.message,
      });
    });
    return res.status(400).json({ status: "error", statusCode: 400, errors });
  }
};

و اینجا هم compare کار میکنه!

ولی وقتی پسورد رو عوض میکنم و اون hash جدید که اومده رو توی دیتابیس ذخیره میکنم

و اینبار که میخواد کاربر لاگین کنه با پسورد جدید نمیشه :)

یعنی ارور میده که پسورد match نیستش

منظورم اینه که اون پسورد جدید رو میگه استباهه و درست campare نمیکنه درحالی که هردوشون با یه salt ساخته میشن و کلا هم موقع ساخت حساب و هم موقع تغییر پسورد اون پسورد به یک شکل hash میشه ولی نمیدونم چره موقع compare اون پسورد جدید رو میگه اشتباهه

اینم کدای ساخت hash هستش:

const bcrypt = require("bcryptjs");

module.exports = async (password) => {
  const salt = await bcrypt.genSalt(10);
  const hashedPassword = await bcrypt.hash(password, salt);
  return hashedPassword;
};

خواهشا کمک کنین یک هفتس پروژم بخواطر این خوابیده

  • 1401/10/14
  • ساعت 15:06

سلام دوست من

خیلی عذرخواهی میکنم که دیر دارم جواب میدم به طور عجیبی ایمیل این سوال رو ندیدم 

مشکل رو برطرف کردی یا هنوزم این مشکل رو داری ؟


  • 1401/10/14
  • ساعت 22:41

خواهش میکنم استاد
بعله هنوز همین مشکل رو دارم
3 4 روز درگیرش بودم
به نتیجه ای هم نرسیدم


  • 1401/10/15
  • ساعت 15:52

سلام خوب هستید.

اگه در قسمت رجیستر با دوره پیش رفتید , ما برای هش کردن پسورد از قابلیت pre که برای mongoose هست استفاده کردیم. اونجا قبل از اینکه user ساخته بشه پسورد هش میشه. شاید مشکل اونجا باشه و دوبار رمز هش میشه و تغییر میکنه.

امیدوارم مشکل حل بشه.


  • 1401/10/15
  • ساعت 21:52

سلام دوست عزیز
نه فکر کنم سوال رو اشتباه متوجه شده باشید
اولین تکه کدی که گذاشتم اگه دقت کنین میبینین که منم از قابلی pre قبل از ذخیره کردن کاربر استفاده کردم 

 


  • 1401/10/15
  • ساعت 22:13

از اونجایی که ما از pre استفاده کردیم نیازی نیست که دستی هش کنی بعد از تغییر رمز

مشکل از همین باید باشه چون ۲ بار داره هش میشه و به همین خاطر مشکل پیش میاد

مثل رمز اول داده شده که خودت دستی هش کردی و زمانی هم که ذخیره میکنی توسط متد نوشته شده درون pre هم کلمه عبور هش شده دستی دوباره هش میشه پس متفاوت خواهد بود

در زمان تغییر رمز عبور فقط رمز جدید رو ذخیره کن خودش هش میشه اتوماتیک

مشکلت باید برطرف بشه


  • 1401/10/16
  • ساعت 17:14

آها بعله استاد کاملا درسته
پسورد دوبار هش میشد
یک بار وقتی من دستی هش میکردم
یکبار هم قبل از سیو

ممنون از شما ❤️


logo-enamadlogo-samandehi