اذهب إلى المحتوى

السؤال

نشر

انا اقوم بمشهادة كورس اكاديمية حسوب لاساسيات node js واقوم بالتطبيق بالتوازي مع مشروعي وهو تطبيق حجز الكتروني يحتوي على واجهات للمدير وواجهات للمستخدمين العادينن ،ولكنني شعرت بالكتير من اللخبطة وعدم سير الامور بشكل جيد ، اريد مساعدة في اخباري هل انا اقوم بالعمل بشكل صحيح ام لا؟ حيت بدأت اول بتكوين المجلد وتهيئة الملفات وتكوين كل models الخاصة بمشروعي ومن تم routes ومن تم controllers ومن تم اردت تجربة الامر على postman ولكن لم يعمل اي شيء. ارجوا مساعدتي وشكرا

fin_pr.zip

Recommended Posts

  • 0
نشر

ما قمتي به بمفردك مجهود جيد جدا من طريقة التقسيم والهيكلية للمجلدات وفصل كل شئ لكي تقوم كل مجموعة من الملفات بالقيام بشئ مخصص بها من أن يكون تعريف مجموعة النماذج في مجلد خاص بها والمسارات أيضا نفس الشئ.

قمت بالإختبار لإنشاء مستخدم جديد في ملف models\user.js يبدو أنه نسيتي الإستيراد للحزمة bcrypt بالإضافة أنه وضعتي في تعريف النموذج أن يكون الاسم unique : true أي لا يتم تكرار نفس الاسم لأي مستخدم أخر في مجموعة المستخدمين ولكن الأفضل أن يتم تكرار الاسم لا مشكلة في ذلك فقط نريد الاميل أن يكون مميز وفريد غير قابل للتكرار ليكون ملف models\user.js نقوم بإضافة تعريف المكتبة أعلي الملف كالأتي ونمسح ,unique: true  من الاسم

const bcrypt = require('bcrypt');

أيضا عند عملية التسجيل نريد أن نضع مسار له ليصبح في ملف routes\users.js بداية سطر 10 كالأتي

router.post('/register', async (req, res) => {
  try {
    const newUser = new User(req.body);
    await newUser.save();
    res.status(201).json(newUser);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

لأنه سوف نقوم بعمل متحكم أخر لتسجيل الدخول بعد هذه التعديلات يمكنك إرسال طلب من برنامج بوست مات لتسجيل مستخدم جديد يكون نوع الطلب POST والمسار له.

http://localhost:3000/api/users/register

وجسم الطلب في بوست مان يكون كالأتي

{
    "name": "mostafa",
    "email": "mostafa@gmail.com",
    "password": "123456",
    "role":"customer"
    
}

ستجدي أنه تم تسجيل مستخدم جديد بدون مشكلة Screenshot2024-08-130343361.thumb.png.e3250e341384ae38854bc5a40c4c037f.png
 

يمكنك تجربة طريقة أفضل ولكن سنقوم ببعض التعديلات، الأفضل بدلا من تعريف المتحكم مباشرة بعد المسار يمكنك نقل كود المتحكم داخل المتحكم reigister بداخل ملف المتحكمات controllers\authcontoller.js ليصبح المتحكم register كالأتي 

exports.register = async (req, res) => {
    try {
        const newUser = new User(req.body);
        await newUser.save();
        res.status(201).json(newUser);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
}

إذا اخترتي الاستمرار في هذه الطريقة يمكنك المتابعة بعد ذلك في ملف routes\auth.js يوجد خطأ في التوجيه وكتبتي نقطة ( . )بدلا  ( , )  وتم كتابة أسماء المتحكمات في كل الحالات login 

// مسارات التسجيل وتسجيل الدخول
router.post('/login'.authController.login)
                    ^               ^^^^^^
router.post('/register'.authController.login)
                       ^               ^^^^^
router.post('/logout'.authController.login)
                     ^               ^^^^^

نقوم بالتعديل ليصبح بهذا الشكل

// مسارات التسجيل وتسجيل الدخول
router.post('/login', authController.login)
router.post('/register', authController.register)
router.post('/logout', authController.logout)

وفي ملف app.js نقوم بتعريف    authRouter وطلب الملف 

const authRouter = require('./routes/auth');

ثم التوجيه له في سطر 27 بدلا من التوجيه إلي usersRouter نقوم بالتوجيه إلى authRouter كالأتي

app.use('/api/users', authRouter);

كلا الطريقتين متاحتين يمكنك إنشاء متحكمات منفصلة لكل مسار له متحكمات خاصة به أو بعد كتابة المسار كتابة كود المتحكم بصورة مباشرة كما في الطريقة الأولى.

إذا واجهتك أي مشكلة أخرى يمكنك السؤال بها مع توضيحها بشكل مفصل لكي يتم مساعدتك بصورة أسرع وأفضل.

  • 0
نشر
بتاريخ 9 ساعة قال Mustafa Mahmoud7:

ما قمتي به بمفردك مجهود جيد جدا من طريقة التقسيم والهيكلية للمجلدات وفصل كل شئ لكي تقوم كل مجموعة من الملفات بالقيام بشئ مخصص بها من أن يكون تعريف مجموعة النماذج في مجلد خاص بها والمسارات أيضا نفس الشئ.

قمت بالإختبار لإنشاء مستخدم جديد في ملف models\user.js يبدو أنه نسيتي الإستيراد للحزمة bcrypt بالإضافة أنه وضعتي في تعريف النموذج أن يكون الاسم unique : true أي لا يتم تكرار نفس الاسم لأي مستخدم أخر في مجموعة المستخدمين ولكن الأفضل أن يتم تكرار الاسم لا مشكلة في ذلك فقط نريد الاميل أن يكون مميز وفريد غير قابل للتكرار ليكون ملف models\user.js نقوم بإضافة تعريف المكتبة أعلي الملف كالأتي ونمسح ,unique: true  من الاسم

const bcrypt = require('bcrypt');

أيضا عند عملية التسجيل نريد أن نضع مسار له ليصبح في ملف routes\users.js بداية سطر 10 كالأتي

router.post('/register', async (req, res) => {
  try {
    const newUser = new User(req.body);
    await newUser.save();
    res.status(201).json(newUser);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

لأنه سوف نقوم بعمل متحكم أخر لتسجيل الدخول بعد هذه التعديلات يمكنك إرسال طلب من برنامج بوست مات لتسجيل مستخدم جديد يكون نوع الطلب POST والمسار له.

http://localhost:3000/api/users/register

وجسم الطلب في بوست مان يكون كالأتي

{
    "name": "mostafa",
    "email": "mostafa@gmail.com",
    "password": "123456",
    "role":"customer"
    
}

ستجدي أنه تم تسجيل مستخدم جديد بدون مشكلة Screenshot2024-08-130343361.thumb.png.e3250e341384ae38854bc5a40c4c037f.png
 

يمكنك تجربة طريقة أفضل ولكن سنقوم ببعض التعديلات، الأفضل بدلا من تعريف المتحكم مباشرة بعد المسار يمكنك نقل كود المتحكم داخل المتحكم reigister بداخل ملف المتحكمات controllers\authcontoller.js ليصبح المتحكم register كالأتي 

exports.register = async (req, res) => {
    try {
        const newUser = new User(req.body);
        await newUser.save();
        res.status(201).json(newUser);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
}

إذا اخترتي الاستمرار في هذه الطريقة يمكنك المتابعة بعد ذلك في ملف routes\auth.js يوجد خطأ في التوجيه وكتبتي نقطة ( . )بدلا  ( , )  وتم كتابة أسماء المتحكمات في كل الحالات login 

// مسارات التسجيل وتسجيل الدخول
router.post('/login'.authController.login)
                    ^               ^^^^^^
router.post('/register'.authController.login)
                       ^               ^^^^^
router.post('/logout'.authController.login)
                     ^               ^^^^^

نقوم بالتعديل ليصبح بهذا الشكل

// مسارات التسجيل وتسجيل الدخول
router.post('/login', authController.login)
router.post('/register', authController.login)
router.post('/logout', authController.login)

وفي ملف app.js نقوم بتعريف    authRouter وطلب الملف 

const authRouter = require('./routes/auth');

ثم التوجيه له في سطر 27 بدلا من التوجيه إلي usersRouter نقوم بالتوجيه إلى authRouter كالأتي

app.use('/api/users', authRouter);

كلا الطريقتين متاحتين يمكنك إنشاء متحكمات منفصلة لكل مسار له متحكمات خاصة به أو بعد كتابة المسار كتابة كود المتحكم بصورة مباشرة كما في الطريقة الأولى.

إذا واجهتك أي مشكلة أخرى يمكنك السؤال بها مع توضيحها بشكل مفصل لكي يتم مساعدتك بصورة أسرع وأفضل.

شكرا جزيلا ولكن لم يعمل عندي بعد

p2.jpeg

fin_pr.zip

  • 0
نشر

الصورة من بوست مان تشير أن الخادم لا يعمل قومي بتشغيله عن طريق الأمر

npm start

ويوجد مشكلة في ملف routes\auth.js حيث كل المسارات توجه إلى المتحكم login 

router.post('/login', authController.login) 
                                     ^^^^^
router.post('/register', authController.login)
                                        ^^^^^
router.post('/logout', authController.login)
                                      ^^^^^

نقوم بالتعديل ليكن كل مسار يوجه للمتحكم الخاص به ليصبح كالأتي

router.post('/login', authController.login)
router.post('/register', authController.register)
router.post('/logout', authController.logout)

يوجد أيضا تكرار في ملف controllers\authcontoller.js للمتحكم register 

exports.register = async (req, res) => {
    try {
        const newUser = new User(req.body);
        await newUser.save();
        res.status(201).json(newUser);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
}

exports.register =async (req, res) => {
    res.json({
        success:true
    })
};

نقوم بمسح المتحكم الثاني المكرر ليتم إنشاء المستخدم بصورة صحيحة.
بعد هذه التعديلات قومي بعملية الحفظ للملفات عن طريق الضغط علي Ctrl + s في لوحة المفاتيح، وإعادة تشغيل الخادم من جديد عن طريق الأمر 

 npm start

ويمكنك إرسال الطلبات من بوست مان سيتم إنشاء المستخدم.

  • 0
نشر
بتاريخ منذ ساعة مضت قال Mustafa Mahmoud7:

الصورة من بوست مان تشير أن الخادم لا يعمل قومي بتشغيله عن طريق الأمر

npm start

ويوجد مشكلة في ملف routes\auth.js حيث كل المسارات توجه إلى المتحكم login 

router.post('/login', authController.login) 
                                     ^^^^^
router.post('/register', authController.login)
                                        ^^^^^
router.post('/logout', authController.login)
                                      ^^^^^

نقوم بالتعديل ليكن كل مسار يوجه للمتحكم الخاص به ليصبح كالأتي

router.post('/login', authController.login)
router.post('/register', authController.register)
router.post('/logout', authController.logout)

يوجد أيضا تكرار في ملف controllers\authcontoller.js للمتحكم register 

exports.register = async (req, res) => {
    try {
        const newUser = new User(req.body);
        await newUser.save();
        res.status(201).json(newUser);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
}

exports.register =async (req, res) => {
    res.json({
        success:true
    })
};

نقوم بمسح المتحكم الثاني المكرر ليتم إنشاء المستخدم بصورة صحيحة.
بعد هذه التعديلات قومي بعملية الحفظ للملفات عن طريق الضغط علي Ctrl + s في لوحة المفاتيح، وإعادة تشغيل الخادم من جديد عن طريق الأمر 

 npm start

ويمكنك إرسال الطلبات من بوست مان سيتم إنشاء المستخدم.

عند تشغيل المشروع بي nodemon تظهر لي هذه الرسالة 
 

C:\Users\HP\Downloads\fin_pr\node_modules\mongoose\lib\drivers\node-mongodb-native\connection.js:219
    throw new MongooseError('The `uri` parameter to `openUri()` must be a ' +
          ^

MongooseError: The `uri` parameter to `openUri()` must be a string, got "undefined". Make sure the first parameter to `mongoose.connect()` or `mongoose.createConnection()` is a string.
    at NativeConnection.createClient (C:\Users\HP\Downloads\fin_pr\node_modules\mongoose\lib\drivers\node-mongodb-native\connection.js:219:11)
    at NativeConnection.openUri (C:\Users\HP\Downloads\fin_pr\node_modules\mongoose\lib\connection.js:823:34)
    at Mongoose.connect (C:\Users\HP\Downloads\fin_pr\node_modules\mongoose\lib\mongoose.js:448:15)
    at Object.<anonymous> (C:\Users\HP\Downloads\fin_pr\app.js:22:10)
    at Module._compile (node:internal/modules/cjs/loader:1358:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
    at Module.load (node:internal/modules/cjs/loader:1208:32)
    at Module._load (node:internal/modules/cjs/loader:1024:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)
    at node:internal/main/run_main_module:28:49

Node.js v20.14.0


وكانه يوجد خطا في قاعدة البيانات ولكن لم افهم السبب؟
 

fin_pr.zip

  • 0
نشر
بتاريخ منذ ساعة مضت قال Raghad Jamal:

عند تشغيل المشروع بي nodemon تظهر لي هذه الرسالة 
 

C:\Users\HP\Downloads\fin_pr\node_modules\mongoose\lib\drivers\node-mongodb-native\connection.js:219
    throw new MongooseError('The `uri` parameter to `openUri()` must be a ' +
          ^

MongooseError: The `uri` parameter to `openUri()` must be a string, got "undefined". Make sure the first parameter to `mongoose.connect()` or `mongoose.createConnection()` is a string.
    at NativeConnection.createClient (C:\Users\HP\Downloads\fin_pr\node_modules\mongoose\lib\drivers\node-mongodb-native\connection.js:219:11)
    at NativeConnection.openUri (C:\Users\HP\Downloads\fin_pr\node_modules\mongoose\lib\connection.js:823:34)
    at Mongoose.connect (C:\Users\HP\Downloads\fin_pr\node_modules\mongoose\lib\mongoose.js:448:15)
    at Object.<anonymous> (C:\Users\HP\Downloads\fin_pr\app.js:22:10)
    at Module._compile (node:internal/modules/cjs/loader:1358:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
    at Module.load (node:internal/modules/cjs/loader:1208:32)
    at Module._load (node:internal/modules/cjs/loader:1024:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)
    at node:internal/main/run_main_module:28:49

Node.js v20.14.0


وكانه يوجد خطا في قاعدة البيانات ولكن لم افهم السبب؟
 

fin_pr.zip 4.37 MB · 0 تنزيلات

هذا الخطأ يشير أنه عند الإتصال لا يوجد رابط قاعدة بيانات للإتصال بها في الدالة ()mongoose.connect 
من الممكن أن يكون السبب أنه تقومي بتشغيل ملف app.js عن طريق nodemon ولا يتم قراء المتغيرات من الملف env. بصورة صحيحة

mongoose.connect(process.env.DB_URL)

لذا قومي بتشغيل المشروع من خلال الملف  bin\www كالأتي  

nodemon ./bin/www

وإذا لم يكن nodemon مثبت يمكنك تثبيته علي الجهاز كالأتي 

npm install -g nodemon

ثم التشغيل من جديد 

nodemon ./bin/www

وسيعمل الخادم معك.

ويمكنك وضع سكربت في في ملف package.json وتعديل هذا الأمر

"scripts": {
    "start": "node ./bin/www"
  },

ليصبح كالأتي 

"scripts": {
        "start": "nodemon ./bin/www"
},

وتشغيل المشروع عبر الأمر 

npm start
  • 0
نشر
بتاريخ 32 دقائق مضت قال Mustafa Mahmoud7:

هذا الخطأ يشير أنه عند الإتصال لا يوجد رابط قاعدة بيانات للإتصال بها في الدالة ()mongoose.connect 
من الممكن أن يكون السبب أنه تقومي بتشغيل ملف app.js عن طريق nodemon ولا يتم قراء المتغيرات من الملف env. بصورة صحيحة

mongoose.connect(process.env.DB_URL)

لذا قومي بتشغيل المشروع من خلال الملف  bin\www كالأتي  

nodemon ./bin/www

وإذا لم يكن nodemon مثبت يمكنك تثبيته علي الجهاز كالأتي 

npm install -g nodemon

ثم التشغيل من جديد 

nodemon ./bin/www

وسيعمل الخادم معك.

ويمكنك وضع سكربت في في ملف package.json وتعديل هذا الأمر

"scripts": {
    "start": "node ./bin/www"
  },

ليصبح كالأتي 

"scripts": {
        "start": "nodemon ./bin/www"
},

وتشغيل المشروع عبر الأمر 

npm start

شكرا جزيلا تمت عملية register بنجاح ولكن ظهرت لي مشكلة في login لم افهم السبب؟
 

db.jpeg

lo.jpeg

re.jpeg

fin_pr.zip

  • 0
نشر

في المتحكم register بتشفير كلمة المرور عن طريق هذا السطر 

// تشفير كلمة المرور
const hashedPassword = await bcrypt.hash(password, 10);

ولكن أيضا في models\user.js في هذه الدالة ()userSchema.pre

userSchema.pre('save', async function (next) {
  if (!this.isModified('password')) return next();
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
  next();
});

تقومي بالتشفير مرة أخري لكلمة المرور قبل الحفظ في قاعدة البيانات وعند تعديل كلمة المرور، أي يتم تشفير كلمة المرور مرتين عند عملية التسجيل لذا نقوم بتعديل المتحكم register ليكون بهذا الشكل 

exports.register = async (req, res) => {
    try {
        // استخراج البيانات من الطلب
        const { name, email, password, role } = req.body;
        // إنشاء مستخدم جديد
        const newUser = new User({
            name,
            email,
            password,
            role,
        });
        // حفظ المستخدم في قاعدة البيانات
        await newUser.save();
        res.status(201).json(newUser);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
};

قمنا بإزالة عملية التشفير في المتحكم وسيتم التشفير مرة واحدة فقط من خلال الدالة ()userSchema.pre الموجودة في models\user.js.

بعد ذلك في المتحكم login تقومي بإستدعاء الدالة generateToken من jwtHelpers وهي غير موجودة في هذا الملف 

const token = jwtHelpers.generateToken(user._id);

نقوم بتعديل هذا السطر

const token = jwtHelpers.sign({ id: user._id, email: user._email });

واستخدام الدالة ()sign وهي الموجودة في jwtHelpers  ليتم إنشاء رموز JWT من خلال إرسال الإيميل والـ id للمستخدم وحفظ الرمز في token، بعد ذلك عليكي بتسجيل المستخدم من جديد وتسجيل الدخول بنفس المستخدم وستكون النتيجة في بوست مان كالأتي

{
    "success": true,
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY2YmI3N2U3NzFkZGE0NTI0NjY3YzFiMCIsImlhdCI6MTcyMzU2MjgzNSwiZXhwIjoxNzIzNTcwMDM1fQ.kgqAcpEGjtGPmSX4aiCQHwHI3-UGTrbVZyOdGDLAAEY"
}

تم تسجيل الدخول بنجاح وإرسال الرمز.

  • 0
نشر
بتاريخ On 13‏/8‏/2024 at 17:30 قال Mustafa Mahmoud7:

في المتحكم register بتشفير كلمة المرور عن طريق هذا السطر 

// تشفير كلمة المرور
const hashedPassword = await bcrypt.hash(password, 10);

ولكن أيضا في models\user.js في هذه الدالة ()userSchema.pre

userSchema.pre('save', async function (next) {
  if (!this.isModified('password')) return next();
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
  next();
});

تقومي بالتشفير مرة أخري لكلمة المرور قبل الحفظ في قاعدة البيانات وعند تعديل كلمة المرور، أي يتم تشفير كلمة المرور مرتين عند عملية التسجيل لذا نقوم بتعديل المتحكم register ليكون بهذا الشكل 

exports.register = async (req, res) => {
    try {
        // استخراج البيانات من الطلب
        const { name, email, password, role } = req.body;
        // إنشاء مستخدم جديد
        const newUser = new User({
            name,
            email,
            password,
            role,
        });
        // حفظ المستخدم في قاعدة البيانات
        await newUser.save();
        res.status(201).json(newUser);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
};

قمنا بإزالة عملية التشفير في المتحكم وسيتم التشفير مرة واحدة فقط من خلال الدالة ()userSchema.pre الموجودة في models\user.js.

بعد ذلك في المتحكم login تقومي بإستدعاء الدالة generateToken من jwtHelpers وهي غير موجودة في هذا الملف 

const token = jwtHelpers.generateToken(user._id);

نقوم بتعديل هذا السطر

const token = jwtHelpers.sign({ id: user._id, email: user._email });

واستخدام الدالة ()sign وهي الموجودة في jwtHelpers  ليتم إنشاء رموز JWT من خلال إرسال الإيميل والـ id للمستخدم وحفظ الرمز في token، بعد ذلك عليكي بتسجيل المستخدم من جديد وتسجيل الدخول بنفس المستخدم وستكون النتيجة في بوست مان كالأتي

{
    "success": true,
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY2YmI3N2U3NzFkZGE0NTI0NjY3YzFiMCIsImlhdCI6MTcyMzU2MjgzNSwiZXhwIjoxNzIzNTcwMDM1fQ.kgqAcpEGjtGPmSX4aiCQHwHI3-UGTrbVZyOdGDLAAEY"
}

تم تسجيل الدخول بنجاح وإرسال الرمز.

تظهر لي هذه الرسالة؟
 

lo.jpeg

fin_pr.zip

  • 0
نشر

لنقوم بتتبع هذا الخطأ

{
    "error": "jwtHelpers.sign is not a function"
}

يخبرنا أن الدالة ()jwtHelpers.sign هي غير دالة أو لا يستطيع التعرف عليها لماذا ذلك نذهب لملف jwtHelpers.js ونرى ما بداخله هل sign هذه عبارة عن دالة أم ماذا 

exports.sign = (payload) => {
    return jwt.sign(payload,secret,{expiresIn})
}

هي بالفعل دالة ولا مشكلة فيها إذا الخطأ أين لاحظي باقي الأكواد في الملف ولاحظي عملية التصدير 

const jwt = require('jsonwebtoken')
const { token } = require('morgan')
const secret = process.env.JWT_SECURT
const expiresIn = process.env.JWT_EXPIRES_IN

const generateToken = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

exports.sign = (payload) => {
^^^^^^^^^^^^
    return jwt.sign(payload,secret,{expiresIn})
}

exports.verify = (token) => {
^^^^^^^^^^^^^^
    try {
       return jwt.verify(token,secret,)
    } catch (e) {
        return false
    }
}

module.exports = {
^^^^^^^^^^^^^^
    generateToken,
};

هناك تداخل بين طريقتين للتصدير في الكود في ملف واحد، يتم استخدام module.exports و exports، وهذا يسبب مشاكل لتجنب الأخطاء، يُفضّل استخدام طريقة واحدة فقط للتصدير وأيضا الدالة generateToken تؤدي نفس وظيفة الدالة sign يمكنك إزالتها.
نقوم بالتعديل ونستخدم أول طريقة للتصدير كالتالي

const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET;
const expiresIn = process.env.JWT_EXPIRES_IN;

const generateToken = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

const sign = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

const verify = (token) => {
    try {
        return jwt.verify(token, secret);
    } catch (e) {
        return false;
    }
};

module.exports = {
    generateToken,
    sign,
    verify
};

قمنا بالتعديل وتجميع كل الدوال وتصديرها دفعة واحدة.

أو يمكنك استخدام الطريقة الثانية كالتالي

const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET;
const expiresIn = process.env.JWT_EXPIRES_IN;

exports.generateToken = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

exports.sign = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

exports.verify = (token) => {
    try {
        return jwt.verify(token, secret);
    } catch (e) {
        return false;
    }
};

قمنا باستخدام exports لكل دالة تريدي تصديرها.

يمكنك الإختيار بين الطريقتين أي طريقة منهم متاحة للاستخدام.

  • 0
نشر
بتاريخ On 14‏/8‏/2024 at 22:19 قال Mustafa Mahmoud7:

لنقوم بتتبع هذا الخطأ

{
    "error": "jwtHelpers.sign is not a function"
}

يخبرنا أن الدالة ()jwtHelpers.sign هي غير دالة أو لا يستطيع التعرف عليها لماذا ذلك نذهب لملف jwtHelpers.js ونرى ما بداخله هل sign هذه عبارة عن دالة أم ماذا 

exports.sign = (payload) => {
    return jwt.sign(payload,secret,{expiresIn})
}

هي بالفعل دالة ولا مشكلة فيها إذا الخطأ أين لاحظي باقي الأكواد في الملف ولاحظي عملية التصدير 

const jwt = require('jsonwebtoken')
const { token } = require('morgan')
const secret = process.env.JWT_SECURT
const expiresIn = process.env.JWT_EXPIRES_IN

const generateToken = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

exports.sign = (payload) => {
^^^^^^^^^^^^
    return jwt.sign(payload,secret,{expiresIn})
}

exports.verify = (token) => {
^^^^^^^^^^^^^^
    try {
       return jwt.verify(token,secret,)
    } catch (e) {
        return false
    }
}

module.exports = {
^^^^^^^^^^^^^^
    generateToken,
};

هناك تداخل بين طريقتين للتصدير في الكود في ملف واحد، يتم استخدام module.exports و exports، وهذا يسبب مشاكل لتجنب الأخطاء، يُفضّل استخدام طريقة واحدة فقط للتصدير وأيضا الدالة generateToken تؤدي نفس وظيفة الدالة sign يمكنك إزالتها.
نقوم بالتعديل ونستخدم أول طريقة للتصدير كالتالي

const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET;
const expiresIn = process.env.JWT_EXPIRES_IN;

const generateToken = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

const sign = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

const verify = (token) => {
    try {
        return jwt.verify(token, secret);
    } catch (e) {
        return false;
    }
};

module.exports = {
    generateToken,
    sign,
    verify
};

قمنا بالتعديل وتجميع كل الدوال وتصديرها دفعة واحدة.

أو يمكنك استخدام الطريقة الثانية كالتالي

const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET;
const expiresIn = process.env.JWT_EXPIRES_IN;

exports.generateToken = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

exports.sign = (payload) => {
    return jwt.sign(payload, secret, { expiresIn });
};

exports.verify = (token) => {
    try {
        return jwt.verify(token, secret);
    } catch (e) {
        return false;
    }
};

قمنا باستخدام exports لكل دالة تريدي تصديرها.

يمكنك الإختيار بين الطريقتين أي طريقة منهم متاحة للاستخدام.

مرحبا 
عند محاولة القيام بعملية اضافة الاعلان حيت الفكرة في مشروعي ان يقوم المدير فقط باضافة صورة الاعلان ويمكن للمستخدم فقط رؤيتها ، ولكن عند تجربة create في المشروع تظهر لي هذه الرسالة في postman
 

cc.png

fin_pr.zip

  • 0
نشر
بتاريخ منذ ساعة مضت قال Raghad Jamal:

مرحبا 
عند محاولة القيام بعملية اضافة الاعلان حيت الفكرة في مشروعي ان يقوم المدير فقط باضافة صورة الاعلان ويمكن للمستخدم فقط رؤيتها ، ولكن عند تجربة create في المشروع تظهر لي هذه الرسالة في postman

fin_pr.zip 4.37 MB · 1 تنزيل

نقوم بتتبع سبب الخطأ نلاحظ أن هذه الرسالة تأتي من ملف middleware\auth.js حيث يوجد خطأ في الكتلة try بسبب فشل في عملية فك التشفير للـ token حيث يوجد خطأ إملائي في كتابة مفتاح التشفير 

const decoded = jwt.verify(token, process.env.JWT_SECRET);
                                              ^^^^^^^^^^

فهو غير موجود في ملف env. والموجود هو JWT_SECURT نقوم بالتعديل ليصبح هذا السطر كالأتي

const decoded = jwt.verify(token, process.env.JWT_SECURT);

بعد ذلك سيعطي الرسالة

Access denied. You do not have the required role

لأنه عند عملية تسجيل الدخول يتم إنشاء الرمز المميز في ملف  controllers\authcontoller.js سطر 48

const token = jwtHelpers.sign({ id: user._id, email: user.email });
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

يتكون الرمز من الـ id ، email ولكن الـ role غير موجودة فعند فك هذا الرمز لا يوجد role إذا نقوم بتعديل هذا السطر ليصبح كالأتي

const token = jwtHelpers.sign({ id: user._id, email: user.email, role: user.role });

الآن عند عملية تسجيل الدخول يتم إنشاء الرمز المميز يتكون الرمز من الـ id ، email ، role.

بعد ذلك في برنامج بوست مان قومي بتسجيل الدخول من جديد ونسخ token ووضعه في headers تحت مفتاح authorization وسيتم إنشاء الإعلان.

  • 0
نشر
بتاريخ On 22‏/8‏/2024 at 04:16 قال Mustafa Mahmoud7:

نقوم بتتبع سبب الخطأ نلاحظ أن هذه الرسالة تأتي من ملف middleware\auth.js حيث يوجد خطأ في الكتلة try بسبب فشل في عملية فك التشفير للـ token حيث يوجد خطأ إملائي في كتابة مفتاح التشفير 

const decoded = jwt.verify(token, process.env.JWT_SECRET);
                                              ^^^^^^^^^^

فهو غير موجود في ملف env. والموجود هو JWT_SECURT نقوم بالتعديل ليصبح هذا السطر كالأتي

const decoded = jwt.verify(token, process.env.JWT_SECURT);

بعد ذلك سيعطي الرسالة

Access denied. You do not have the required role

لأنه عند عملية تسجيل الدخول يتم إنشاء الرمز المميز في ملف  controllers\authcontoller.js سطر 48

const token = jwtHelpers.sign({ id: user._id, email: user.email });
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

يتكون الرمز من الـ id ، email ولكن الـ role غير موجودة فعند فك هذا الرمز لا يوجد role إذا نقوم بتعديل هذا السطر ليصبح كالأتي

const token = jwtHelpers.sign({ id: user._id, email: user.email, role: user.role });

الآن عند عملية تسجيل الدخول يتم إنشاء الرمز المميز يتكون الرمز من الـ id ، email ، role.

بعد ذلك في برنامج بوست مان قومي بتسجيل الدخول من جديد ونسخ token ووضعه في headers تحت مفتاح authorization وسيتم إنشاء الإعلان.

حسنا الان قمت مبدئيا بكتابة routes و controllers الخاصه بمشروعي وتجربتها على postman مالخطوة القادمة المفترض ان اقوم بها ، ولو يوجد اي ملاحظات على مشروعي من فضلك اخبرني بها.
 

fin_pr.zip

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...