البرمجة

الاستيثاق بالتوكن في Node.js

الاستيثاق عبر مفتاح المستخدم المشفر (Token Authentication) في تطبيقات Node.js و React

مقدمة

في عصر التطبيقات الحديثة، أصبح ضمان أمان المستخدمين وحماية بياناتهم من أهم التحديات التي تواجه المطورين. واحدة من الطرق الأكثر استخداماً لتحقيق هذا الهدف هي تقنية الاستيثاق عبر مفتاح المستخدم المشفر، أو ما يُعرف بـ Token Authentication. تعتمد هذه التقنية على إصدار “رمز” (Token) يتم تشفيره وتحويله إلى مفتاح فريد لكل مستخدم، يستخدم لاحقًا للتحقق من هويته وتأمين التواصل بين العميل والخادم. في هذا المقال سيتم تناول شرح تفصيلي وعميق لمفهوم الاستيثاق عبر التوكن، كيفية تطبيقه في بيئة Node.js من جهة الخادم (Back-end) وReact من جهة العميل (Front-end)، وأفضل الممارسات لضمان أمان التطبيقات.


مفهوم الاستيثاق عبر مفتاح المستخدم المشفر (Token Authentication)

الاستيثاق هو العملية التي يتم فيها التحقق من هوية المستخدم والتأكد من أنه مخول للوصول إلى الموارد أو الخدمات المطلوبة. بخلاف الطرق التقليدية التي تعتمد على الجلسات (Sessions) والكوكيز (Cookies)، تعتمد تقنية الاستيثاق عبر التوكن على إرسال رمز مُشفر يمثل هوية المستخدم بعد تسجيل الدخول. هذا الرمز هو عبارة عن مفتاح مشفر يحتوي على بيانات المستخدم وبعض الخصائص الأمنية.

لماذا نستخدم التوكن بدلاً من الجلسات؟

  • عدم الاعتماد على التخزين على الخادم: التوكنات تكون مخزنة على العميل فقط، مما يجعل الخادم لا يحتاج للاحتفاظ بحالة الجلسة، وبالتالي يقلل الضغط على الخادم.

  • التوسع السهل: في التطبيقات الموزعة أو التي تعمل على أكثر من خادم، يمكن التحقق من التوكن مباشرة دون الحاجة إلى مشاركة حالة الجلسة بين الخوادم.

  • الأمان: يمكن تشفير التوكن وتوقيعه رقميًا لضمان عدم التلاعب به.

  • المرونة: يمكن استخدام التوكن في أنظمة متعددة (مواقع، تطبيقات هواتف ذكية، APIs).


أنواع التوكنات المستخدمة في الاستيثاق

يوجد عدة أنواع من التوكنات المستخدمة في عمليات الاستيثاق، أبرزها:

  1. JWT (JSON Web Token): الأكثر شيوعاً وانتشاراً، يعتمد على تنسيق JSON يحتوي على بيانات المستخدم ويكون موقعًا رقمياً.

  2. Opaque Tokens: رموز غير مفهومة من قبل العميل، وتُستخدم عادة مع أنظمة OAuth2.

  3. Custom Tokens: رموز يتم تصميمها بشكل مخصص حسب متطلبات التطبيق.

يركز هذا المقال على استخدام JWT كونه الحل الأمثل والمنتشر في بيئة Node.js وReact.


آلية عمل JWT في الاستيثاق

يتكون JWT من ثلاثة أجزاء:

  • Header (الرأس): يحتوي على نوع التوكن وطريقة التشفير المستخدمة.

  • Payload (الحمل): يحتوي على البيانات التي ترغب في نقلها مثل معرف المستخدم ووقت انتهاء صلاحية التوكن.

  • Signature (التوقيع): يُستخدم للتحقق من أن التوكن لم يتم تغييره.

عند تسجيل المستخدم، يتم إنشاء JWT مشفر يحمل بيانات معينة، ويرسل إلى العميل ليخزنها (عادة في localStorage أو sessionStorage). في كل طلب لاحق، يُرسل التوكن مع الطلب ليتم التحقق من صحة المستخدم قبل السماح بالوصول للموارد.


خطوات تطبيق الاستيثاق عبر JWT في تطبيق Node.js و React

1. إعداد بيئة العمل

في Node.js (الخادم)

  • تثبيت الحزم الأساسية مثل express و jsonwebtoken و bcryptjs للتحقق من كلمات السر.

bash
npm install express jsonwebtoken bcryptjs cors body-parser

في React (العميل)

  • إنشاء مشروع React باستخدام create-react-app أو أي أداة تفضيلية.

  • إضافة مكتبة axios لإجراء طلبات HTTP.

bash
npm install axios

2. بناء خادم Node.js لإنشاء وإدارة التوكن

أ. تسجيل المستخدم (Signup)

عند تسجيل مستخدم جديد، يتم تشفير كلمة المرور قبل تخزينها في قاعدة البيانات.

js
const bcrypt = require('bcryptjs'); app.post('/signup', async (req, res) => { const { username, password } = req.body; const hashedPassword = await bcrypt.hash(password, 10); // تخزين username و hashedPassword في قاعدة البيانات res.status(201).send("User created"); });

ب. تسجيل الدخول (Login) وإصدار التوكن

عند طلب تسجيل الدخول، يتم مقارنة كلمة المرور المدخلة مع النسخة المشفرة في قاعدة البيانات، وإذا تطابقت، يتم إنشاء JWT وإرساله للعميل.

js
const jwt = require('jsonwebtoken'); app.post('/login', async (req, res) => { const { username, password } = req.body; // استرجاع بيانات المستخدم من قاعدة البيانات حسب username const user = await findUser(username); if(!user) return res.status(404).send('User not found'); const validPassword = await bcrypt.compare(password, user.password); if(!validPassword) return res.status(401).send('Invalid password'); const token = jwt.sign({ id: user._id, username: user.username }, 'your_jwt_secret_key', { expiresIn: '1h' }); res.json({ token }); });

ج. Middleware للتحقق من التوكن

قبل السماح بالوصول إلى الموارد المحمية، يقوم الخادم بالتحقق من صحة التوكن:

js
function verifyToken(req, res, next) { const token = req.headers['authorization']; if(!token) return res.status(403).send('Token required'); jwt.verify(token, 'your_jwt_secret_key', (err, decoded) => { if(err) return res.status(401).send('Invalid token'); req.user = decoded; next(); }); }

3. بناء واجهة React لاستخدام التوكن

أ. تسجيل الدخول من جانب العميل

يقوم المستخدم بإدخال بياناته، ثم إرسالها إلى الخادم باستخدام axios، واستقبال التوكن وتخزينه محليًا.

jsx
import axios from 'axios'; import { useState } from 'react'; function Login() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = async (e) => { e.preventDefault(); const response = await axios.post('http://localhost:5000/login', { username, password }); localStorage.setItem('token', response.data.token); }; return ( <form onSubmit={handleSubmit}> <input type="text" onChange={e => setUsername(e.target.value)} placeholder="Username" /> <input type="password" onChange={e => setPassword(e.target.value)} placeholder="Password" /> <button type="submit">Loginbutton> form> ); }

ب. استخدام التوكن في طلبات محمية

عند طلب بيانات محمية من الخادم، يجب تضمين التوكن في رأس الطلب.

js
const token = localStorage.getItem('token'); axios.get('http://localhost:5000/protected-route', { headers: { Authorization: token } }) .then(response => console.log(response.data)) .catch(error => console.error(error));

كيفية تحسين الأمان في الاستيثاق عبر التوكن

1. استخدام HTTPS

من الضروري استخدام بروتوكول HTTPS لتشفير الاتصال بين العميل والخادم، مما يحمي التوكن من التعرض للاعتراض (man-in-the-middle).

2. تخزين التوكن بطريقة آمنة

  • يُفضل تخزين التوكن في ذاكرة الجلسة (sessionStorage) بدلاً من localStorage لتقليل خطر التعرض لهجمات XSS.

  • يمكن تخزين التوكن في ملفات الكوكيز مع ضبط الخصائص HttpOnly و Secure لمنع الوصول إليه عبر جافاسكريبت.

3. تحديد صلاحية زمنية للتوكن

يجب ضبط مدة صلاحية التوكن بحيث لا تكون طويلة جداً لتقليل خطر استخدامه من قبل جهة غير مخولة.

4. استخدام التوكن المحدث (Refresh Token)

لتقليل مدة صلاحية التوكن، يمكن استخدام توكن محدث (Refresh Token) الذي يسمح للمستخدم بالحصول على توكن جديد دون الحاجة لتسجيل الدخول مجدداً. هذا يحسن الأمان مع المحافظة على تجربة مستخدم جيدة.


مقارنة بين الجلسات (Sessions) و التوكن (Token Authentication)

الخاصية الجلسات (Sessions) التوكن (Token Authentication)
تخزين حالة الجلسة على الخادم لا تخزن على الخادم (stateless)
قابلية التوسع صعبة في الأنظمة الموزعة سهلة جداً للتوسع
الأمان تعتمد على إدارة الجلسات والكوكيز تعتمد على التشفير والتوقيع
الأداء قد تؤثر على أداء الخادم أخف على الخادم بسبب عدم الحاجة لتخزين الحالة
استخدام في APIs غير ملائم مثالي للاستخدام في تطبيقات الويب والهواتف الذكية

حالات استخدام Token Authentication في التطبيقات الحديثة

  • تطبيقات SPA (Single Page Applications): مثل React و Angular حيث يتم فصل الواجهة الأمامية عن الخادم.

  • APIs المفتوحة: يمكن توفير وصول مؤمن للمستخدمين أو الأطراف الثالثة عبر التوكن.

  • تطبيقات الجوال: حيث يُستخدم التوكن لتفويض المستخدمين بدون الحاجة للاحتفاظ بحالة الجلسة.


الخاتمة

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


المراجع

  1. JWT.io – JSON Web Tokens

  2. Node.js Authentication with JWT