NestJS — Node.js للمؤسسات

المصادقة بـ JWT

18 دقيقة الدرس 27 من 30

المصادقة بـ JWT

التحقّق من كلمة المرور مرّة لا يكفي — يُجري المستخدم طلبات كثيرة بعدها، ولا يمكنك طلب كلمة المرور في كل مرّة. يحلّ JWT (رمز ويب JSON) هذا: بعد الدخول تُصدِر رمزًا موقّعًا، يرسله العميل في كل طلب، ويتحقّق منه خادمك دون بحث في قاعدة البيانات. وهذا عمود فقري للمصادقة عديمة الحالة.

ما هو JWT

الـ JWT نصّ موقّع بثلاثة أجزاء مفصولة بنقاط: ترويسة، وحمولة (ادّعاءات كمعرّف المستخدم وانتهاء الصلاحية)، وتوقيع. ولأنّه موقّع بسرّ يعرفه خادمك وحده، يستطيع الخادم الوثوق بالحمولة دون تخزين أي جلسة.

الـ JWT موقّع لا مُشفّر. يستطيع أي أحد فكّ ترميز الحمولة وقراءتها. لا تضع أسرارًا أبدًا (كلمات مرور، بيانات حسّاسة) فيها — ضع فقط معرّفات غير حسّاسة كمعرّف المستخدم والأدوار.

إصدار رمز عند الدخول

ثبّت @nestjs/jwt واضبطها (السرّ والانتهاء من الإعداد). بعد تحقّق الاستراتيجية المحلية من المستخدم، وقّع رمزًا:

// JwtModule.registerAsync({ ... secret, signOptions: { expiresIn: '15m' } }) import { JwtService } from '@nestjs/jwt'; @Injectable() export class AuthService { constructor(private jwt: JwtService) {} login(user: { id: number; email: string }) { const payload = { sub: user.id, email: user.email }; return { access_token: this.jwt.sign(payload) }; } }
ادّعاء sub هو المكان القياسي للموضوع (معرّف المستخدم). إبقاء الحمولات صغيرة وقياسية يُبقي الرموز مُدمَجة وقابلة للتشغيل البيني.

استراتيجية JWT

لحماية المسارات، تستخرج استراتيجية JWT الرمزَ من ترويسة Authorization: Bearer، وتتحقّق من التوقيع، وتُعيد معلومات المستخدم من الحمولة:

import { Strategy, ExtractJwt } from 'passport-jwt'; import { PassportStrategy } from '@nestjs/passport'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor(config: ConfigService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: config.get('JWT_SECRET'), }); } async validate(payload: { sub: number; email: string }) { return { userId: payload.sub, email: payload.email }; // يصبح request.user } }

حماية المسارات

@UseGuards(AuthGuard('jwt')) @Get('profile') getProfile(@Request() req) { return req.user; // { userId, email } من الرمز المُتحقَّق }

إن كان الرمز مفقودًا أو منتهيًا أو مُعبَثًا به، يرفض الحارس الطلب بـ 401 Unauthorized تلقائيًا.

عديم الحالة وقابل للتوسّع

لماذا تتوسّع JWTs. لأنّ التحقّق مجرّد فحص توقيع، تستطيع أي نسخة خادم التحقّق من رمز دون مخزن جلسات مشترك. وهذا يجعل JWTs مثالية لواجهات API الموسّعة أفقيًا والخدمات المصغّرة — بلا جلسات لاصقة، ولا قاعدة بيانات جلسات مركزية.
أبقِ رموز الوصول قصيرة العمر. الـ JWT المسروق صالح حتى ينتهي، ولا طريقة سهلة لإبطال رمز عديم الحالة في منتصف عمره. الانتهاء القصير (مثلًا 15 دقيقة) يحدّ الضرر — وهو بالضبط سبب وجود رموز التحديث، التالية.

الخلاصة

الـ JWT رمز موقّع يحمل ادّعاءات غير حسّاسة (كمعرّف المستخدم في sub). أصدِره عند الدخول بـ JwtService.sign()، واحمِ المسارات باستراتيجية JWT + AuthGuard('jwt') التي تتحقّق من رمز Bearer بلا حالة — دون مخزن جلسات. لا تضع أسرارًا في الحمولة، وأبقِ رموز الوصول قصيرة العمر. تاليًا: رموز التحديث، التي تحلّ مشكلة الانتهاء القصير بأمان.