البرمجة

إنشاء نظام مستخدمين في Express

إنشاء مدونة باستخدام Express (الجزء الثالث): إنشاء نظام المستخدمين

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


إعداد قاعدة بيانات المستخدمين

لبداية قوية، يجب تحديد بنية المستخدم في قاعدة البيانات. في تطبيقات Node.js، غالبًا ما يتم استخدام MongoDB كقاعدة بيانات NoSQL، مع استخدام Mongoose كمكتبة لنمذجة البيانات.

نموذج المستخدم User Schema

js
const mongoose = require('mongoose'); const bcrypt = require('bcrypt'); const UserSchema = new mongoose.Schema({ username: { type: String, required: true, unique: true, minlength: 3, maxlength: 30 }, email: { type: String, required: true, unique: true, lowercase: true, trim: true }, password: { type: String, required: true, minlength: 6 }, createdAt: { type: Date, default: Date.now } }); // تشفير كلمة المرور قبل حفظها UserSchema.pre('save', async function (next) { if (!this.isModified('password')) return next(); this.password = await bcrypt.hash(this.password, 10); next(); }); module.exports = mongoose.model('User', UserSchema);

إنشاء واجهات API للتسجيل وتسجيل الدخول

بمجرد إعداد النموذج، تكون الخطوة التالية هي إنشاء نقاط النهاية (API endpoints) للتسجيل وتسجيل الدخول. يتم ذلك باستخدام Express Router لضمان فصل المنطق وتنظيم الكود.

تسجيل مستخدم جديد

js
const express = require('express'); const router = express.Router(); const User = require('../models/User'); const jwt = require('jsonwebtoken'); router.post('/register', async (req, res) => { const { username, email, password } = req.body; try { const userExists = await User.findOne({ email }); if (userExists) return res.status(400).json({ message: 'المستخدم موجود مسبقاً' }); const newUser = new User({ username, email, password }); await newUser.save(); const token = jwt.sign({ id: newUser._id }, process.env.JWT_SECRET, { expiresIn: '1d' }); res.status(201).json({ token, user: { id: newUser._id, username: newUser.username, email: newUser.email } }); } catch (error) { res.status(500).json({ message: 'خطأ في الخادم' }); } });

تسجيل الدخول

js
router.post('/login', async (req, res) => { const { email, password } = req.body; try { const user = await User.findOne({ email }); if (!user) return res.status(404).json({ message: 'المستخدم غير موجود' }); const isMatch = await bcrypt.compare(password, user.password); if (!isMatch) return res.status(400).json({ message: 'كلمة المرور غير صحيحة' }); const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1d' }); res.json({ token, user: { id: user._id, username: user.username, email: user.email } }); } catch (error) { res.status(500).json({ message: 'خطأ في الخادم' }); } });

حماية المسارات باستخدام Middleware للمصادقة

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

middleware للتحقق من التوكن

js
const jwt = require('jsonwebtoken'); function authenticate(req, res, next) { const token = req.header('Authorization'); if (!token) return res.status(401).json({ message: 'لا يوجد توكن، الدخول مرفوض' }); try { const decoded = jwt.verify(token, process.env.JWT_SECRET); req.user = decoded; next(); } catch (err) { res.status(401).json({ message: 'توكن غير صالح' }); } } module.exports = authenticate;

تطبيق الحماية على مسار معين

js
const authenticate = require('../middleware/authenticate'); router.get('/profile', authenticate, async (req, res) => { try { const user = await User.findById(req.user.id).select('-password'); res.json(user); } catch (err) { res.status(500).json({ message: 'خطأ في الخادم' }); } });

بنية المجلدات لتنظيم الكود

يُستحسن استخدام بنية مجلدات واضحة تسهل صيانة وتطوير التطبيق مع الوقت:

pgsql
project-root/ │ ├── models/ │ └── User.js ├── routes/ │ └── auth.js ├── middleware/ │ └── authenticate.js ├── controllers/ │ └── authController.js (اختياري للفصل بين المنطق والمسارات) ├── config/ │ └── db.js (للاتصال بقاعدة البيانات) ├── .env ├── server.js └── package.json

إعداد البيئة وملفات التكوين

يجب تخزين معلومات حساسة مثل مفاتيح JWT في ملف بيئة .env:

ini
PORT=5000 JWT_SECRET=yourSuperSecretKey MONGO_URI=mongodb://localhost:27017/express_blog

ويتم قراءتها في التطبيق باستخدام dotenv:

js
require('dotenv').config();

استخدام Postman لاختبار الواجهات

تُعد أداة Postman مثالية لاختبار نقاط النهاية:

نوع الطلب عنوان المسار الوصف
POST /api/auth/register تسجيل مستخدم جديد
POST /api/auth/login تسجيل الدخول
GET /api/auth/profile عرض ملف المستخدم (محمي)

تخزين التوكن في العميل

بعد تسجيل الدخول بنجاح، يتم إرجاع توكن JWT للعميل. يمكن تخزينه في:

  • localStorage: جيد للجلسات الطويلة، لكنه معرض لهجمات XSS.

  • HTTP-only cookies: أكثر أمانًا، خاصة عند دمج Express مع React أو أي واجهة أمامية.


الجدول العام لبنية نظام المستخدمين

المكون الوصف
User Schema يمثل نموذج المستخدم في قاعدة البيانات ويشمل التشفير المسبق لكلمة المرور
Register API يسجل مستخدمًا جديدًا بعد التحقق من التكرار ويصدر توكن JWT
Login API يتحقق من بيانات الدخول ويصدر توكن JWT للمستخدم
Auth Middleware يتحقق من صلاحية التوكن ويحمي المسارات الخاصة
بنية المجلدات تنظيم الكود في ملفات واضحة لتسهيل الصيانة
Postman أداة لاختبار صحة واجهات API

الجوانب الأمنية الإضافية

لضمان حماية المستخدمين وبياناتهم، ينبغي الأخذ بعين الاعتبار ما يلي:

  • تقييد محاولات الدخول (Rate Limiting): لمنع الهجمات من نوع brute-force.

  • التحقق من صحة المدخلات (Validation): باستخدام مكتبات مثل express-validator أو Joi.

  • استخدام HTTPS: لتشفير البيانات المرسلة بين العميل والخادم.

  • تشفير كلمة المرور باستخدام Salt: كما يوفر bcrypt تلقائيًا.

  • إبطال الجلسات: عبر تعديل توقيت صلاحية التوكن أو استخدام قوائم سوداء.


التكامل مع أنظمة التعليقات أو المقالات

بعد إنشاء نظام المستخدمين، يمكن ربطه مع أنظمة أخرى في المدونة، مثل:

  • تحديد مؤلف المقال عبر معرف المستخدم.

  • السماح للمستخدمين بنشر تعليقات أو التفاعل مع المحتوى.

  • منح صلاحيات خاصة للمشرفين أو المدراء عبر نظام الأدوار.


الخلاصة المعمارية

يمثل نظام المستخدمين حجر الأساس في تطبيق المدونة المعتمد على Express، فهو يوفر قاعدة يمكن البناء عليها لتقديم وظائف أعمق مثل إنشاء المحتوى، تعديل المقالات، والتفاعل الاجتماعي. يتطلب النظام تفكيرًا عميقًا في الجوانب الأمنية والمعمارية لتقديم تجربة موثوقة وآمنة للمستخدمين. بالاعتماد على تقنيات حديثة مثل JWT وMongoose، يمكن تحقيق ذلك بكفاءة ومرونة عالية.


المراجع:

  1. Mongoose Documentation – https://mongoosejs.com

  2. JWT Guide – https://jwt.io/introduction