رموز JWT في TypeScript: دليل شامل مع مكتبة jsonwebtoken
\n\nJSON Web Token (JWT) هو معيار مفتوح (RFC 7519) لإنشاء رموز وصول تعتمد على تنسيق JSON. يُستخدم JWT على نطاق واسع للمصادقة وتبادل المعلومات بين العميل والخادم. في TypeScript، بفضل التصنيف الصارم، يصبح العمل مع JWT مريحًا وآمنًا بشكل خاص. في هذه المقالة، سننظر في كيفية استخدام المكتبة الشهيرة jsonwebtoken في TypeScript لإنشاء رموز JWT والتحقق منها وإدارتها.
التثبيت والإعداد
\n\nللبدء، سنقوم بتثبيت الحزم اللازمة:
\n\nnpm install jsonwebtoken\nnpm install -D @types/jsonwebtoken\n\nالحزمة الأولى هي المكتبة نفسها، والثانية هي أنواع TypeScript لها. بعد التثبيت، سننشئ ملفًا باسم jwt.service.ts حيث سنخزن كل منطق العمل مع الرموز.
إنشاء رمز JWT
\n\nالوظيفة الرئيسية لـ jsonwebtoken هي sign(). لنلقِ نظرة على استخدامها مع التصنيف:
import jwt from 'jsonwebtoken';\n\ninterface TokenPayload {\n userId: number;\n email: string;\n role: 'user' | 'admin';\n}\n\nconst createAccessToken = (payload: TokenPayload): string => {\n const secret = process.env.JWT_SECRET || 'default_secret';\n const options: jwt.SignOptions = {\n expiresIn: '15m', // الرمز صالح لمدة 15 دقيقة\n algorithm: 'HS256',\n };\n\n return jwt.sign(payload, secret, options);\n};\n\nهام: لا تقم أبدًا بتخزين المفتاح السري في الكود. استخدم متغيرات البيئة (ملف .env).
التحقق وفك تشفير الرمز
\n\nللتحقق من صحة الرمز، تُستخدم وظيفة verify(). تقوم تلقائيًا بالتحقق من التوقيع وتاريخ انتهاء الصلاحية:
const verifyToken = (token: string): TokenPayload => {\n const secret = process.env.JWT_SECRET || 'default_secret';\n\n try {\n const decoded = jwt.verify(token, secret) as TokenPayload;\n return decoded;\n } catch (error) {\n if (error instanceof jwt.TokenExpiredError) {\n throw new Error('انتهت صلاحية الرمز');\n }\n if (error instanceof jwt.JsonWebTokenError) {\n throw new Error('رمز غير صالح');\n }\n throw error;\n }\n};\n\nلاحظ تحويل النوع as TokenPayload — هذا يضمن أن TypeScript سيعرف بنية البيانات المفكوكة.
رموز التحديث: تمديد الجلسة
\n\nعمليًا، رموز الوصول (access tokens) تعيش لفترة قصيرة (15-30 دقيقة)، لذا نحتاج إلى آلية لتحديثها. لهذا، يُستخدم رمز تحديث (refresh token) بعمر أطول:
\n\nconst createRefreshToken = (payload: TokenPayload): string => {\n const secret = process.env.JWT_REFRESH_SECRET || 'refresh_secret';\n const options: jwt.SignOptions = {\n expiresIn: '7d', // أسبوع\n algorithm: 'HS256',\n };\n\n return jwt.sign(payload, secret, options);\n};\n\nconst refreshAccessToken = (refreshToken: string): string => {\n const secret = process.env.JWT_REFRESH_SECRET || 'refresh_secret';\n\n try {\n const decoded = jwt.verify(refreshToken, secret) as TokenPayload;\n // يمكن التحقق مما إذا كان رمز التحديث قد تم إلغاؤه في قاعدة البيانات\n return createAccessToken({\n userId: decoded.userId,\n email: decoded.email,\n role: decoded.role,\n });\n } catch {\n throw new Error('رمز تحديث غير صالح');\n }\n};\n\nMiddleware لـ Express في TypeScript
\n\nيتطلب دمج JWT مع Express.js إنشاء middleware. إليك النسخة المصنفة:
\n\nimport { Request, Response, NextFunction } from 'express';\n\ninterface AuthRequest extends Request {\n user?: TokenPayload;\n}\n\nconst authMiddleware = (req: AuthRequest, res: Response, next: NextFunction) => {\n const authHeader = req.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res