استفد من بنية Nest المهيكلة لبناء واجهات برمجة تطبيقات REST آمنة وفعالة.
تعد Express.js تقنية رائعة لبناء واجهات برمجة تطبيقات REST آمنة وقوية ، ومع ذلك ، فهي لا توفر بنية محددة مسبقًا. تسمح لك طبيعته المبسطة بمعالجة الجوانب الأساسية مثل التوجيه وتنظيم الكود والتدابير الأمنية إما يدويًا أو عن طريق الاستفادة من البرامج الوسيطة والمكتبات المتاحة.
في المقابل ، يقدم Nest.js ، المبني أعلى Express.js و Node.js ، مستوى أعلى من التجريد يوفر هيكلًا واضحًا ، ونهجًا قويًا لتنظيم التعليمات البرمجية ، وتنفيذًا مبسطًا تفاصيل. بشكل أساسي ، يوفر Nest.js بنية أكثر تنظيماً لبناء واجهات برمجة تطبيقات وخدمات خلفية فعالة وآمنة.
إنشاء مشروع Nest.js
للبدء ، تحتاج أولاً إلى تثبيت سطر أوامر Nest.js (CLI) بشكل عام عن طريق تشغيل الأمر أدناه:
npm أنا -g @ nestjs / cli
بمجرد اكتمال التثبيت ، امض قدمًا وأنشئ مشروعًا جديدًا عن طريق تشغيل:
عش جديد jwt-api
بعد ذلك ، سيطالبك Nest.js CLI باختيار مدير الحزم لتثبيت التبعيات. في هذا البرنامج التعليمي ، سنستخدم npm ، مدير حزمة العقدة. يختار npm وانتظر بينما يقوم CLI بإنشاء مشروع Nest.js أساسي وتثبيت جميع ملفات التكوين المطلوبة والاعتماديات الأولية المطلوبة لتشغيل التطبيق.
بعد إعداد المشروع ، انتقل إلى دليل المشروع وابدأ خادم التطوير.
cd nest-jwt-api
بدء تشغيل npm
أخيرًا ، قم بتشغيل الأمر أدناه لتثبيت الحزم التي سنستخدمها لهذا المشروع.
npm install mongodb mongoose @ nestjs / mongoose @ types / bcrypt bcrypt jsonwebtoken @ nestjs / jwt
يمكنك العثور على رمز هذا المشروع في هذا مستودع جيثب.
تكوين اتصال قاعدة بيانات MongoDB
قم بإعداد قاعدة بيانات MongoDB محليًا أو تكوين كتلة MongoDB على السحابة. بعد إعداد قاعدة البيانات ، انسخ سلسلة URI لاتصال قاعدة البيانات ، وأنشئ ملف .env ملف في الدليل الجذر لمجلد مشروعنا ، والصقه في سلسلة الاتصال:
MONGO_URI = "سلسلة الاتصال"
بعد ذلك ، قم بتحديث ملف app.module.ts في ال src ملف الدليل لتكوين النمس على النحو التالي:
يستورد { وحدة } من"@ nestjs / مشترك";
يستورد {ConfigModule} من"@ nestjs / config";
يستورد {MongooseModule} من"@ nestjs / النمس";
يستورد {AppController} من"./app.controller";
يستورد {AppService} من"./app.service";
يستورد {UserAuthModule} من"./user-auth/user-auth.module";@وحدة({
الواردات: [
ConfigModule.forRoot ({
envFilePath: ".env",
isGlobal: حقيقي,
}),
MongooseModule.forRoot (process.env. MONGO_URI) ،
UserAuthModule ،
],
وحدات التحكم: [AppController] ،
الموفرون: [AppService] ،
})
يصدّرفصل AppModule {}
تعمل الشفرة المقدمة على تكوين ثلاث وحدات أساسية لتطبيق Nest.js: ConfigModule لتكوين البيئة ، النمس لإنشاء اتصال MongoDB ، و UserAuthModule لمصادقة المستخدم. يرجى ملاحظة أنه ، في هذه المرحلة ، قد يحدث خطأ منذ UserAuthModule لم يتم تعريفه بعد ، لكننا سننشئه في القسم التالي.
إنشاء وحدة مصادقة المستخدم
للحفاظ على رمز نظيف وجيد التنظيم ، قم بإنشاء وحدة مصادقة مستخدم عن طريق تشغيل الأمر التالي.
nest g المصادقة على المستخدم
تقوم أداة Nest.js CLI بإنشاء ملفات الوحدة المطلوبة تلقائيًا. بالإضافة إلى ذلك ، سيتم تحديث app.module.ts ملف يتضمن التغييرات اللازمة المتعلقة بوحدة مصادقة المستخدم.
يمكنك اختيار إنشاء ملفات تكوين المشروع الرئيسية يدويًا ، ومع ذلك ، فإن أداة CLI تبسط هذه العملية عن طريق إنشاء العناصر المطلوبة تلقائيًا ، بالإضافة إلى تحديث التغييرات وفقًا لذلك في ال app.module.ts ملف.
قم بإنشاء مخطط المستخدم
داخل مصادقة المستخدم مجلد في src الدليل ، قم بإنشاء ملف المخططات / user-auth.schema.ts ملف ، وأضف التعليمات البرمجية التالية لإنشاء مخطط Mongoose لملف مستخدم نموذج
يستورد {Prop ، Schema ، SchemaFactory} من"@ nestjs / النمس";
يستورد { وثيقة } من'النمس';@مخطط({الطوابع الزمنية: حقيقي })
يصدّرفصل مستخدم {
@دعم()
اسم المستخدم: خيط;
@دعم()
كلمة المرور: خيط;
}
يصدّريكتب UserDocument = المستخدم والمستند ؛
يصدّرمقدار ثابت UserSchema = SchemaFactory.createForClass (مستخدم) ،
إنشاء خدمة مصادقة المستخدم
الآن ، دعنا ننشئ خدمة مصادقة المستخدم التي ستدير منطق المصادقة لواجهة برمجة تطبيقات REST عن طريق تشغيل الأمر أدناه:
ترخيص المستخدم لخدمة nest g
سيقوم هذا الأمر بإنشاء ملف user-auth.service.ts ملف داخل دليل المستخدم المصادقة. افتح هذا الملف وقم بتحديثه بالرمز التالي.
- أولاً ، قم بإجراء عمليات الاستيراد التالية.
يستورد {Injectable، NotFoundException، Logger، UnauthorizedException} من"@ nestjs / مشترك";
يستورد {InjectModel} من"@ nestjs / النمس";
يستورد { نموذج } من'النمس';
يستورد { مستخدم } من"./schemas/user-auth.schema";
يستورد * مثل bcrypt من"bcrypt";
يستورد {JwtService} من"@ nestjs / jwt"; - ثم قم بإنشاء ملف UserAuthService فئة تضم وظائف تسجيل المستخدم وتسجيل الدخول واسترداد جميع مسارات بيانات المستخدم.
تضمين التغريدة()
يصدّرفصل UserAuthService {
خاص للقراءة فقط المسجل = جديد المسجل (UserAuthService.name) ؛
البناء(تضمين التغريدة(اسم المستخدم) خاص userModel: نموذج, خاص jwtService: JwtService ) {}
غير متزامن مستخدم (اسم المستخدم: خيط، كلمة المرور: خيط): يعدخيط }> {
يحاول {
مقدار ثابت التجزئة = انتظر bcrypt.hash (كلمة المرور ، 10);
انتظرهذا.userModel.create ({اسم المستخدم ، كلمة المرور: التجزئة}) ؛
يعود { رسالة: "تم تسجيل المستخدم بنجاح" };
} يمسك (خطأ) {
يرميجديدخطأ("حدث خطأ أثناء تسجيل المستخدم");
}
}غير متزامن تسجيل الدخول المستخدم (اسم المستخدم: خيط، كلمة المرور: خيط): يعد<خيط> {
يحاول {
مقدار ثابت المستخدم = انتظرهذا.userModel.findOne ({username}) ،
لو (!مستخدم) {
يرميجديد NotFoundException ('لم يتم العثور على المستخدم');
}
مقدار ثابت passwordMatch = انتظر bcrypt.compare (كلمة المرور ، كلمة مرور المستخدم) ؛
لو (! passwordMatch) {
يرميجديد استثناء غير مصرح به ('اعتماد تسجيل الدخول غير صالح');
}
مقدار ثابت الحمولة = {userId: user._id} ،
مقدار ثابت رمز = هذا.jwtService.sign (حمولة) ؛
يعود رمز.
} يمسك (خطأ) {
وحدة التحكم.log (خطأ) ؛
يرميجديد استثناء غير مصرح به ("حدث خطأ أثناء تسجيل الدخول");
}
}
غير متزامن getUsers (): يعد
{
يحاول {
مقدار ثابت المستخدمون = انتظرهذا.userModel.find ({}) ،
يعود المستخدمين ؛
} يمسك (خطأ) {
هذا.logger.error (`` حدث خطأ أثناء استرداد المستخدمين: $ {error.message}`);
يرميجديدخطأ("حدث خطأ أثناء استرداد المستخدمين");
}
}
}
ال UserAuthService تطبق class منطق تسجيل المستخدم وتسجيل الدخول واسترجاع بيانات المستخدم. يستخدم userModel للتفاعل مع قاعدة البيانات وتنفيذ الإجراءات المطلوبة بما في ذلك تجزئة كلمة المرور أثناء التسجيل والتحقق من صحة بيانات اعتماد تسجيل الدخول وأخيرًا إنشاء رموز JWT بعد النجاح المصادقة.
تنفيذ حراسة التوثيق
لضمان أمن الموارد الحساسة ، من الضروري قصر الوصول حصريًا على المستخدمين المصرح لهم. يتم تحقيق ذلك من خلال فرض إجراء أمني يفرض وجود JWT صالح في طلبات API اللاحقة التي تم إجراؤها لنقاط النهاية المحمية ، وفي هذه الحالة ، المستخدمين طريق. في ال مصادقة المستخدم الدليل ، قم بإنشاء ملف auth.guard.ts ملف وإضافة الرمز أدناه.
يستورد {CanActivate، ExecutionContext، Injectable، UnauthorizedException} من"@ nestjs / مشترك";
يستورد {JwtService} من"@ nestjs / jwt";
يستورد { طلب } من'يعبر';
يستورد {مفتاح السر} من"./config";تضمين التغريدة()
يصدّرفصل AuthGuard الأدوات يمكن تنشيط {
البناء(خاص jwtService: JwtService) {}
غير متزامن canActivate (السياق: ExecutionContext): يعد<قيمة منطقية> {
مقدار ثابت request = Context.switchToHttp (). getRequest () ؛
مقدار ثابت رمز = هذا.extractTokenFromHeader (طلب) ؛
لو (! رمز) {
يرميجديد UnauthorizedException () ؛
}
يحاول {
مقدار ثابت الحمولة = انتظرهذا.jwtService.verifyAsync (الرمز المميز ، {
السر: secretKey.secret ،
});
طلب['مستخدم'] = الحمولة ؛
} يمسك {
يرميجديد UnauthorizedException () ؛
}
يعودحقيقي;
}
خاص extractTokenFromHeader (الطلب: الطلب): خيط | غير معرف {
مقدار ثابت [يكتب، token] = request.headers.authorization؟ .split (' ')?? [];
يعوديكتب"حامل"? رمز مميز: غير معرف;
}
}
الكود ينفذ أ يحمي، كما هو محدد في الوثائق الرسمية ، لحماية المسارات والتأكد من أن المستخدمين المصادق عليهم الذين لديهم رمز JWT صالح فقط يمكنهم الوصول إليها.
فهو يستخرج رمز JWT من عنوان الطلب ، ويتحقق من صحتها باستخدام امتداد JwtService ، وتخصيص الحمولة التي تم فك تشفيرها إلى طلب ['مستخدم'] خاصية لمزيد من المعالجة. إذا كان الرمز المميز مفقودًا أو غير صالح ، فسيتم طرح ملف استثناء غير مصرح به لمنع الوصول إلى الطريق المحمي.
الآن ، ابتكر config.ts ملف في نفس الدليل ، وأضف الكود أدناه.
يصدّرمقدار ثابت مفتاح سري = {
سر: "القيمة السرية".,
};
يُستخدم هذا المفتاح السري للتوقيع والتحقق من صحة JWTs. من الضروري تخزين القيمة الرئيسية بشكل آمن لمنع الوصول غير المصرح به وحماية سلامة JWTs.
تحديد وحدة تحكم API
قم بإنشاء وحدة تحكم تتعامل مع نقاط نهاية API لمصادقة المستخدم.
nest g تحكم المستخدم المصادقة
بعد ذلك ، انسخ الكود الوارد في هذا ملف مستودع جيثب، وإضافته إلى ملف user-auth.controller.ts ملف — يحدد نقاط النهاية لتسجيل المستخدم وتسجيل الدخول واسترداد بيانات المستخدم. ال UseGuards (AuthGuard) تم تضمين المصمم لفرض المصادقة على getUsers نقطة النهاية ، مما يضمن منح حق الوصول للمستخدمين المصادق عليهم فقط.
قم بتحديث ملف user-auth.module.ts
لتعكس التغييرات التي تم إجراؤها على المشروع ، قم بتحديث ملف user-auth.module.ts ملف لتكوين الوحدات النمطية والخدمات ووحدات التحكم اللازمة لمصادقة المستخدم.
يستورد {وحدة ، NestModule ، MiddlewareConsumer} من"@ nestjs / مشترك";
يستورد {JwtModule} من"@ nestjs / jwt";
يستورد {UserAuthController} من"./user-auth.controller";
يستورد {UserAuthService} من"./user-auth.service";
يستورد {MongooseModule} من"@ nestjs / النمس";
يستورد {UserSchema} من"./schemas/user-auth.schema";
يستورد {مفتاح السر} من"./config";@وحدة({
الواردات: [
MongooseModule.forFeature ([{الاسم: 'مستخدم'، المخطط: UserSchema}]) ،
JwtModule.register ({
السر: secretKey.secret ،
خيارات التوقيع: {expiresIn: "1 ساعة" },
}),
],
وحدات التحكم: [UserAuthController] ،
الموفرون: [UserAuthService] ،
})
يصدّرفصل UserAuthModule الأدوات NestModule {
تكوين (المستهلك: MiddlewareConsumer) {
}
}
أخيرًا ، قم بتدوير خادم التطوير واختبر نقاط نهاية API باستخدام Postman.
بدء تشغيل npm
إنشاء واجهات برمجة تطبيقات REST لـ Nest.js الآمنة
يتطلب إنشاء واجهات برمجة تطبيقات آمنة لـ Nest.js REST نهجًا شاملاً يتجاوز مجرد الاعتماد على JWTs للمصادقة والتفويض. في حين أن JWTs مهمة ، من المهم بنفس القدر تنفيذ تدابير أمنية إضافية.
بالإضافة إلى ذلك ، من خلال إعطاء الأولوية للأمان في كل مرحلة من مراحل تطوير واجهة برمجة التطبيقات ، يمكنك ضمان أمان أنظمة الواجهة الخلفية الخاصة بك.