بناء أداة توليد صور مدفوعة: تطبيق عملي لتكامل الذكاء الاصطناعي مع أنظمة الدفع
45 دقيقة
١٥ يناير ٢٠٢٦
المرحلة 1 من 4
تصميم البنية الأساسية ونظام المصادقة
الفصل الأول: تصميم البنية الأساسية ونظام المصادقة
في هذا الفصل، سنضع حجر الأساس للتطبيق. سنبدأ بتصميم بنية المشروع وتهيئة بيئة العمل، ثم ننتقل إلى بناء نظام مصادقة قوي وآمن باستخدام JWT (JSON Web Tokens) وbcrypt. هذه الخطوة حاسمة لحماية نقاط النهاية (endpoints) الخاصة بالدفع وتوليد الصور.
1.1 هيكلة المشروع وتهيئة البيئة
قبل كتابة أي سطر برمجي، يجب تنظيم الملفات والمجلدات بطريقة قابلة للصيانة والتوسع. سنتبع بنية مقسمة حسب المسؤولية (Separation of Concerns).
- config/: لتخزين إعدادات قاعدة البيانات، ومفاتيح JWT، وإعدادات Stripe.
- models/: لتعريف نماذج بيانات MongoDB (مثل User, ImageGeneration).
- routes/: لتحديد نقاط النهاية (endpoints) للتطبيق (مصادقة، صور، دفعات).
- controllers/: للتعامل مع منطق الأعمال لكل route.
- middleware/: للوظائف الوسيطة مثل التحقق من JWT والصلاحيات.
- utils/: للدوال المساعدة (مثل توليد JWT، التحقق من الصلاحية).
ابدأ بتهيئة مشروع Node.js وتثبيت الحزم الأساسية:
// تهيئة package.json
// قم بتنفيذ الأمر في الطرفية:
// npm init -y
// تثبيت الحزم الأساسية
// npm install express mongoose bcryptjs jsonwebtoken dotenv cors
// npm install -D nodemon
// ملف .env (يجب إضافته إلى .gitignore)
PORT=5000
MONGODB_URI=your_mongodb_connection_string
JWT_SECRET=your_super_secret_jwt_key_here
STRIPE_SECRET_KEY=your_stripe_secret_key
ملاحظة: استخدم متغيرات البيئة (environment variables) عبر حزمة `dotenv` لحماية المعلومات الحساسة مثل مفاتيح API وكلمات سر قاعدة البيانات. لا تدمج هذه القيم أبداً مباشرة في الكود المصدري.
1.2 إنشاء نموذج المستخدم (User Model)
نموذج المستخدم هو قلب نظام المصادقة. سنحدد الحقول الضرورية لتسجيل المستخدم وتخزين بياناته بشكل آمن.
// models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: [true, 'اسم المستخدم مطلوب'],
unique: true,
trim: true,
minlength: [3, 'اسم المستخدم يجب أن يكون 3 أحرف على الأقل']
},
email: {
type: String,
required: [true, 'البريد الإلكتروني مطلوب'],
unique: true,
lowercase: true,
match: [/^\S+@\S+\.\S+$/, 'يرجى إدخال بريد إلكتروني صالح']
},
password: {
type: String,
required: [true, 'كلمة المرور مطلوبة'],
minlength: [6, 'كلمة المرور يجب أن تكون 6 أحرف على الأقل'],
select: false // لا تُرجع كلمة المرور تلقائياً عند الاستعلام
},
credits: {
type: Number,
default: 0 // رصيد المستخدم لشراء توليد الصور
},
isAdmin: {
type: Boolean,
default: false
},
createdAt: {
type: Date,
default: Date.now
}
});
// تشفير كلمة المرور قبل الحفظ في قاعدة البيانات
UserSchema.pre('save', async function(next) {
// فقط إذا تم تعديل حقل كلمة المرور
if (!this.isModified('password')) return next();
try {
// توليد "ملح" (salt) وتشفير كلمة المرور
const salt = await bcrypt.genSalt(12);
this.password = await bcrypt.hash(this.password, salt);
next();
} catch (error) {
next(error);
}
});
// دالة لمقارنة كلمة المرور المدخلة مع المشفرة
UserSchema.methods.comparePassword = async function(candidatePassword) {
return await bcrypt.compare(candidatePassword, this.password);
};
module.exports = mongoose.model('User', UserSchema);
الكود أعلاه يوضح:
- المخطط (Schema): يحدد شكل وقيود بيانات المستخدم.
- Middleware (`pre('save')`): يتم تنفيذه تلقائياً قبل حفظ المستخدم. يستخدم `bcrypt` لتوليد hash آمن لكلمة المرور باستخدام خوارزمية قوية.
- الدالة `comparePassword`: طريقة مخصصة على النموذج لمقارنة كلمة المرور المدخلة أثناء تسجيل الدخول مع النسخة المشفرة المخزنة.
- `select: false`: إعداد أمان مهم يمنع إرجاع hash كلمة المرور في استعلامات البحث إلا عند طلبها صراحة.
تحذير: لا تستخدم أبداً خوارزميات تشفير ضعيفة مثل MD5 أو SHA-1 لكلمات المرور. استخدم دائمًا مكتبات مصممة خصيصًا مثل `bcrypt` أو `argon2` التي توفر التشفير البطيء والمقاوم لهجمات القوة الغاشمة.
1.3 تنفيذ تسجيل المستخدم وتسجيل الدخول (Auth Endpoints)
الآن سننشئ نقاط النهاية (routes) والمنطق (controllers) للسماح للمستخدمين بالتسجيل وتسجيل الدخول. عند نجاح العملية، سنرجع رمز JWT للعميل.
1.3.1 إنشاء الراوت والكونترولر
// routes/auth.js
const express = require('express');
const router = express.Router();
const { register, login } = require('../controllers/authController');
router
جاري تحميل التقييمات...