استخدام JWT وMiddleware في Node.js لإنشاء أدوار Admin وUser بأمان

تعزيز أمان مشروعك: كيفية إنشاء أدوار Admin وUser في Node.js بأمان
أفضل طرق تحسين أداء نظام Roles في No de.js: Admin أم User


إنشاء Roles لمشروعك في Nodejs لمعرفة الحساب ادمن ام مستخدم عادي

في تطبيقات الويب الحديثة، من الضروري التحكم في الصلاحيات المختلفة للمستخدمين بناءً على دورهم. قد يكون لديك مثلاً مشرفون (Admins) يقومون بإدارة النظام بالكامل، ومدراء (Managers) يديرون جزءًا معينًا من التطبيق، ومستخدمون عاديون (Users) لديهم صلاحيات محدودة. في هذا المقال، سنوضح كيفية إنشاء نظام أدوار (Roles) باستخدام Node.js لتحديد ما إذا كان الحساب هو حساب مشرف أم مستخدم عادي.


يُعدّ إنشاء أدوار (Roles) في مشروع Nodejs أمرًا ضروريًا للتحكم في صلاحيات المستخدمين وتحديد ما يُمكنهم الوصول إليه والقيام به في النظام.

يُمكنك استخدام أدوار مختلفة لتمييز المستخدمين حسب وظائفهم أو صلاحياتهم، مثل:

  • المسؤول (Admin): يُمكنه الوصول إلى جميع الوظائف في النظام وإجراء التعديلات عليها.
  • المستخدم العادي: يُمكنه الوصول إلى الوظائف الأساسية في النظام فقط.


إنشاء ملف مخصص لكتابة انواع ال Roles

لدينا ثلاث انواع وهما مستخدم عادي ومدير والادمن سوف نقوم بعمل ملف يحتوي على هذه المتغيرات , أول خطوة في بناء نظام الصلاحيات هي تحديد الأدوار التي يحتاجها مشروعك. في مثالنا، قمنا بإنشاء ملف userRoles.js الذي يحتوي على تعريفات الأدوار:

userRoles.js
const userRoles = {
    ADMIN: "ADMIN",
    USER: "USER",
    MANGER: "MANGER",
}

module.exports = userRoles;

قمنا بإنشاء كائن userRoles يحتوي على ثلاثة أدوار رئيسية: ADMIN، USER، وMANAGER.
ثم قمنا بتصدير دالة allowedTo التي تأخذ قائمة من الأدوار وتتحقق مما إذا كان دور المستخدم الحالي (req.currentUser.role) مسموحًا له بالوصول إلى المسار.

إنشاء middleware للتاكد من Roles

هنا نتاكد من النوع هل هو ضمن ما سوف يتم ارساله مثلا لو لدينا صفحة لاضافة منتجات وتكون من خلال الادمن فقط ما سوف نقوم به هو اخباره ان المسؤول عن القيام بهذه العمليه هو الادمن ونرسل له قيمة rolse الخاصه بالمستخدم وهو سوف يقارن اذا توافقت ام لا .

allowedTo.js
const appError = require("../utils/appError");

module.exports = (...roles) => {    
    return (req, res, next) => {
        if(!roles.includes(req.currentUser.role)) {
            return next(appError.create('this role is not authorized', 401))
        }
        next();
    }
}

اضافة قيمة role داخل userModel

هنا نقوم بعمل قيمة للمتغيرات ونضع قيمة افتراضيه بحيث نخبره ان القيمه سوف تكون احد الثلاث قيم فقط والافتراضي هو مستخدم عادي وهذا يكون خلال عملية انشاء الحساب 
user.model.js
const userSchema = new mongoose.Schema({
role: {
        type: String, // ["USER", "ADMIN", "MANGER"]
        enum: [userRoles.USER, userRoles.ADMIN, userRoles.MANGER],
        default: userRoles.USER
    },
});

  1. أضفنا حقل role إلى نموذج المستخدم.
  2. استخدمنا الخاصية enum لتحديد الأدوار المسموح بها فقط (USER، ADMIN، MANAGER).
  3. حددنا الدور الافتراضي لكل مستخدم جديد ليكون USER.

التاكد من صحة ال rolse في route

في هذا الجزء سوف يكون المخصص في عملية الاضافة هو المدير فقط ولكن في عملية الحذف يمكن للمدير والادمن الحذف وذا تحقق الشرط ينتقل الى الخطوة التي تليها وهيا تنفيذ الامر .

courses.route.js
const allowedTo = require('../middleware/allowedTo');


router.route('/')
            .get(courseController.getAllCourses)
            .post(verifyToken, allowedTo(userRoles.MANGER), validationSchema(), courseController.addCourse);


router.route('/:courseId')
            .get(courseController.getCourse)
            .patch(courseController.updateCourse)
            .delete(verifyToken, allowedTo(userRoles.ADMIN, userRoles.MANGER), courseController.deleteCourse);

تخزين قيمة role داخل token اثناء التسجيل nodejs

في هذا الجزء سوف نقوم بتخزين البيانات بداخل ملف controller وهنا يعمل عند تسجيل حساب جديد يتم تسجيل البيانات .

users.controller.js
const newUser = new User({
        firstName,
        lastName,
        email,
        password: hashedPassword,
        role,
        avatar: req.file.filename
    })

    // generate JWT token 
    const token = await generateJWT({email: newUser.email, id: newUser._id, role: newUser.role});
    newUser.token = token;

الحصول على قيمة role من token واستخدامه على مستوى المشروع nodejs

في هذا الجزء نقوم بالتاكد من صحة ال token وايضا نقوم بالحصول على المعلومات من خلاله وهنا ايضا يتم تخزين معلومات التوكن داخل req.currentUser ونستطيع استخدامه في اي مكان في المشروع .
verfiyToken.js
const jwt = require('jsonwebtoken');
const httpStatusText = require('../utils/httpStatusText');
const appError = require('../utils/appError');

const verifyToken = (req, res, next) => {
    const authHeader = req.headers['Authorization'] || req.headers['authorization'];
    if(!authHeader) {
        const error = appError.create('token is required', 401, httpStatusText.ERROR)
        return next(error);
    }

    const token = authHeader.split(' ')[1];
    try {
        const currentUser = jwt.verify(token, process.env.JWT_SECRET_KEY);
	//-----  this ----//
        req.currentUser = currentUser;
        next();

    } catch (err) {
        const error = appError.create('invalid token', 401, httpStatusText.ERROR)
        return next(error);
    }   
    
}

module.exports = verifyToken;

  1. استخدام JWT: تأكد من استخدام JSON Web Tokens (JWT) لتخزين دور المستخدم في توكن التوثيق.
  2. اختبارات الوحدة: اكتب اختبارات للتحقق من أن كل دور لديه الصلاحيات الصحيحة.
  3. توثيق API: قم بتوثيق واجهة برمجة التطبيقات الخاصة بك لتوضيح الأدوار المطلوبة لكل مسار.

إدارة الصلاحيات والأدوار في تطبيقات Node.js هي خطوة أساسية لبناء تطبيقات آمنة ومنظمة. باستخدام الأدوات المناسبة مثل mongoose وmiddleware، يمكنك بسهولة إنشاء نظام قوي لإدارة الأدوار مثل ADMIN، USER، وMANAGER.
مع هذا النظام، يمكنك ضمان أن كل مستخدم لديه حق الوصول فقط إلى الموارد التي يحتاجها، مما يعزز الأمان والثقة في تطبيقك.


تعليقات