كيفية فصل الواجهة الأمامية + الواجهة الخلفية باستخدام Rails API و Nuxt.js و Devise-JWT

لقد كنت معجبًا كبيرًا بـ Ruby on Rails منذ الأيام الأولى ، وعلى الرغم من أن عالم الويب قد تحرك كثيرًا منذ ذلك الحين ، فإن Rails لا يزال لديه مكان في هذا المشهد ، لتطوير التطبيقات السريعة برمز نظيف يمكن صيانته.

لكن العالم قد تغير. أدى ظهور تطبيقات الويب التقدمية (وتطبيقات الأجهزة المحمولة المعروضة عليها) إلى عالم يريد فيه المستخدمون واجهة تفاعلية قوية من تطبيقاتهم على الويب: النقر على الروابط وتنزيل الصفحة التالية من واجهة المستخدم من الخادم يبدو وكأنه شيء فعله الناس في 2000S.

لقد أصبحت مؤخرًا معجبًا كبيرًا بـ Nuxt.js ، والتي بدأت أفكر فيها ك "سكك الواجهة الأمامية". Nuxt هو إطار لتطوير التطبيقات يستند إلى Webpack و Vue.js. إنه يحتوي على خلفية ، ولكن في تجربتي ، يضيء حقًا عند استخدامه في إنشاء وضع لإنشاء تطبيقات بدون خادم يمكن نشرها على خدمات تؤدي عادةً محتوى ثابتًا ، مثل GitHub Pages أو S3. تتضمن أمثلة التطبيقات التي لا تحتوي على خادم والتي قمت بإنشائها باستخدام Nuxt Maple وموقع الويب الخاص بشركتي ، وكلاهما يعمل على صفحات GitHub.

يوجد الكثير من المشاركات في عالم Rails في الوقت الحالي حول Rails API: إصدار تم تجريده من Rails والذي يمكن استخدامه لإنشاء تطبيقات خادم فقط على واجهة برمجة التطبيقات والتي تصل بعد ذلك إلى ما تريده: تطبيقات الجوال أو التطبيقات المستندة إلى المستعرض مثل كما بنيت مع Nuxt.

ولكن يبدو أن هناك ندرة في الأدلة حول كيفية القيام بذلك بالفعل ، خاصةً عند التفكير في المصادقة. كيف يمكنك توفير واجهة تسجيل دخول في الواجهة الأمامية تسجل المستخدمين في الواجهة الخلفية؟

لذلك هنا يذهب. مدونة طويلة إلى حد ما تدور ، خطوة بخطوة ، وهي عملية إنشاء تطبيق ويب بسيط مفصول في Rails API و Nuxt ، وبناء نظام مصادقة أساسي بشكل لا يصدق باستخدام Devise-JWT.

ملاحظة: يفترض هذا الدليل معرفة جيدة بشكل معقول بـ Rails ومعرفة عابرة لـ Vue.js وفهم أساسي على الأقل لـ Docker.

إذا كنت ترغب في رؤية التطبيق النهائي ، أو واجهتك مشكلة في أي وقت ، يمكنك الرجوع إلى شفرة المصدر على جيثب.

الجزء 1: خلق بيئة التطوير

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

أولاً ، دعنا ننشئ تطبيقات Rails API و Nuxt فارغة:

يفترض هذا أنه تم تثبيت "CLIs" و "clue" على الجهاز المضيف الخاص بك. يمكنك بالطبع استخدام صور Docker ل CLIs هذه إذا لم تقم بذلك.

الخيارات المتعددة لقضبان السكك الحديدية الجديدة تجعلها تتخطى إضافة اختبارات ، Action Cable و Spring ، وكذلك لمنعها من تشغيل الحزمة على جهازك المضيف (سنريد تشغيل هذا داخل Docker). وبالمثل ، نستخدم إدخال إنشاء قفل الغزل لإنشاء ملف yarn.lock دون الحاجة إلى تثبيت الحزم.

بعد ذلك ، قم بإنشاء Dockerfiles الصغيرة لإنشاء بيئات الواجهة الأمامية والخلفية ، ورسو السفن - compose.yml لوصف كيفية ملاءمة قاعدة البيانات معًا:

بعض الأشياء التي يجب ملاحظتها هنا:

  • يتم تثبيت الأحجار الكريمة وحزم الغزل في وحدات التخزين المثبتة. سيمنعك هذا من الحاجة إلى إعادة إنشاء صورة Docker بأكملها في كل مرة تقوم فيها بتغيير Gemfile أو package.json.
  • يفترض هذا معرف المستخدم المضيف الخاص بك هو 1001 ويقوم بإنشاء مستخدم داخل كل حاوية بنفس معرف المستخدم. إذا كان معرف المستخدم مختلفًا ، فيمكنك تعيين متغير بيئة UID قبل الإنشاء وسيقوم بتمرير ذلك كوسيلة للبناء.
  • ربما تريد إضافة وحدات node_modules إلى الواجهة الأمامية. dockerignore & .gitignore والبائع / الحزمة ، log ، tmp ، إلى الواجهة الخلفية. بهذه الطريقة لن يتم نسخها خلال وقت الإنشاء.

الآن حان الوقت لبناء كل شيء:

سبب احتياجك لتشغيل الحزمة والغزل بعد البناء هو أن ملف الإنشاء الخاص بك يعمل على تثبيت وحدات تخزين مضيفك في الحاويات بحيث تحتاج إلى تثبيت الحزم في مجلدات المضيف بالإضافة إلى الصور التي يتم استخدامها لإنشاء الحاويات.

بضعة أشياء أخيرة قبل أن تتمكن من رفع هذه البيئة:

  1. قم بتحرير database.yml لتعيين اسم المضيف على "db" والمستخدم إلى "postgres".
  2. قم بتعديل package.json لتغيير البرنامج النصي "dev" إلى "HOST = 0.0.0.0 nuxt" (بحيث يكون مرئيًا على الجهاز المضيف).
  3. قم بتشغيل "docker-compose run backend rails db: create" لإنشاء قاعدة بيانات التطوير.

كل شيء على ما يرام ، يجب أن تكون الآن قادرًا على الكتابة:

عامل ميناء يؤلف

والبيئة الخاصة بك (قاعدة البيانات ، الواجهة الخلفية) سوف تدور. يمكنك التحقق من واجهات الويب على: 8080 و: 3000 وسترى الصفحات الافتراضية لكل منها.

الواجهة الأمامية هي في الواقع خادم webpack-dev ، والذي قد لا تستخدمه إذا كنت برنامج ترميز Rails في المدرسة القديمة. تنعكس التغييرات التي تجريها على واجهة المستخدم فورًا في متصفحك ، دون الحاجة إلى إعادة التحميل. هذا تغيير مثير!

حق! احصل على مشروعك ملتزمًا بالتحكم في الإصدار ، ثم لنبدأ في بناء بعض الأشياء!

الجزء 2: جعلهم يتحدثون مع بعضهم البعض

دعونا نبني أول طريقة لواجهة برمجة التطبيقات. سنقوم فقط بإنشاء مورد يسمى "مثال" له اسم ولون ، وإنشاء 3 منها للاختبار.

قم بتحرير route.rb لنقل المسار الجديد إلى نطاق api ، وإضافة طريقة فهرس بسيطة إلى ExamplesController:

تأكد من أن ApplicationController يخبر جميع أطفاله أنهم قادرون على الاستجابة لطلبات JSON (هذا ضروري لبعض الأحجار الكريمة ، مثل Devise):

[تحرير: قد تحتاج بالفعل إلى الانتظار حتى يتم تثبيت Devise للقيام بذلك ، لأنه يبدو أن هناك مشكلة تبعية إذا قمت بذلك مبكرًا. اسمحوا لي أن أعرف إذا كان لديك أي أفكار حول كيفية تقديم هذه في وقت مبكر.]

الآن يجب أن تكون قادرًا على زيارة http: // localhost: 8080 / api / أمثلة لرؤية واجهة برمجة التطبيقات الخاصة بك قيد التنفيذ:

الآن للجزء الممتع: سنربط الواجهة الأمامية بالواجهة الخلفية. لكن أولاً ، لا تنسَ الالتزام بالتحكم في الإصدار!

سنستخدم axios للتحدث إلى واجهة برمجة التطبيقات (API) ، و vuetify كمجموعة أدوات واجهة المستخدم. (يمكنك استخدام HTML و CSS في Vue ، ولكن هناك أيضًا تكاملات UI أعمق: vuetify عبارة عن مجموعة من أدوات واجهة المستخدم استنادًا إلى تصميم المواد.) كلاهما لهما تكاملات مع Nuxt المتاحة في المجتمع ، لذلك دعونا نقوم بتثبيت هذه:

عامل الإرساء يؤلف غزل الواجهة الأمامية add @ nuxtjs / axios @ nuxtjs / vuetify

وأضف إلى ملف التكوين Nuxt:

(من الواضح أنه في الإنتاج ، ستحتاج إلى نقل إعدادات axios إلى البيئة ، لكن من الجيد الآن تغييرها على أنها رمز ثابت.)

الآن دعنا نستبدل التخطيطات / default.vue والصفحات / index.vue التي أنشأها Nuxt لنا:

default.vue هو تخطيط vuetify قياسي ، مع شريط أدوات يحتوي على رابط للصفحة الرئيسية. يخبرك خيار nuxt بالرابط باستخدام جهاز توجيه Nuxt للتعامل مع الرابط ، بدلاً من القيام بذلك في المتصفح.

index.vue أكثر تعقيدًا بقليل: يتم استدعاء الأسلوب mount () عند تهيئة القالب ، وهذا بدوره يستدعي updateExamples () ، والذي يستخدم تكامل axios لتعيين متغير الأمثلة على نتائج طريقة API. تحتوي على مجموعة تفاعلية من التجانبات يتم ملؤها تلقائيًا استنادًا إلى كل ما هو موجود في الأمثلة (لذلك ستكون فارغة في البداية ثم تقوم بالملء عند اكتمال طريقة API).

ولكن إذا حاولت زيارة هذا الآن ، فستتلقى خطأً مؤسفًا:

لا يُسمح باستخدام جافا سكريبت JavaScript للاستعلام عن نقاط النهاية على المجالات الأخرى ما لم تقم هذه النطاقات بتعيين رؤوس CORS بشكل مناسب. لحسن الحظ ، توقعت Rails API أننا نريد ذلك!

قم بإلغاء ربط سطر 'rack-cors' في Gemfile وإلغاء فك الشفرة في cors.rb ، وتغيير example.com إلى localhost: 3000 (أو *). تثبيت جوهرة:

عامل ميناء يؤلف تشغيل -u حزمة الجذر الخلفية

ثم أعد تشغيل حاويات الإرساء عن طريق ضرب Ctrl-C على الأعمدة قيد التشغيل والقيام بإعداد عامل الإرساء مرة أخرى. عبرت الأصابع الآن سترى شيئًا كهذا:

فوردعالم! يعرض تطبيق الواجهة الأمامية البيانات مباشرةً من الواجهة الخلفية! حاول إضافة مثال جديد إلى قاعدة البيانات (على سبيل المثال "qux / cyan") لتأكيد الواجهة الأمامية الخاصة بك بالفعل على استرداد البيانات من الواجهة الخلفية الخاصة بك.

الالتزام بالتحكم في الإصدار والحصول على نفسك القهوة. التالي هو المصادقة وأصعب قليلاً!

الجزء 3: المصادقة مع Devise-JWT

Devise-JWT هو امتداد لمكتبة مصادقة Rails الشهيرة Devise لإضافة دعم لـ JSON Web Token ، وهو تطبيق شائع لتسجيل الدخول الفردي. إذا كنت تتواجد حولك في Google ، فستجد الكثير من الأشخاص يقولون إنه من السهل إضافة JWT لتضع نفسك ، ولكن ليس إذا كنت ترغب في الاستفادة بشكل صحيح من جميع ميزات Devise ، وليس إذا كنت تريد تسجيل الخروج (أي إنشاء الرمز غير صالح).

أولاً ، أضف "devise" و "devise-jwt" إلى Gemfile وقم بتشغيل:

عامل ميناء يؤلف تشغيل -u حزمة الجذر الخلفية

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

> القضبان g ابتكار: تثبيت
> القضبان g ابتكار المستخدم
> القضبان ديسيبل: الهجرة

ليس لدى Devise-JWT مثبّت ، لكن لديه إرشادات تثبيت جيدة. عليك أن تقرر كيف تريد إبطال الرموز. ذهبت لخيار القائمة السوداء. فمثلا:

> القضبان g model jwt_blacklist jti: string: index exp: datetime

قم بتحرير الترحيل لإضافة قيمة خالية: خطأ وإزالة الطوابع الزمنية وإضافة "تضمين Devise :: JWT :: RevocationStrategies :: Blacklist" إلى النموذج.

لتمكين JWT ، ستحتاج إلى إضافة jwt_secret إلى ملف secrets.yml (يمكنك إنشاء أسرار جديدة باستخدام "rails secret") ، وإضافة هذا إلى devise.rb:

تحتاج إلى تحديث سطر التصميم في نموذج المستخدم الخاص بك لإضافة:

: jwt_authenticatable ، jwt_revocation_strategy: JwtBlacklist

شغّل "rails db: migrate" مرة أخرى لإنشاء قائمتك السوداء.

انقل المسار devise_for في route.rb إلى: api scope وأعد تشغيل الحاويات.

يجب أن تكون قادرًا الآن على اختبار API الخاص بك باستخدام شيء مثل YARC. أولاً ، قم بإنشاء مستخدم في وحدة التحكم في Rails:

> القضبان ج
>> User.create! (البريد الإلكتروني: 'test@example.com' ، كلمة المرور: 'password')

ثم حاول إنشاء رسالة POST إلى نقطة نهاية / api / users / sign_in التي تبدو كما يلي:

وسترى رأس التخويل يعود مع تسجيل الدخول الناجح:

رائع. نحن نصل إلى هناك ، أعدك!

نريد استخدام مكتبة المصادقة الخاصة بشركة Nuxt ، والتي تتوقع إرجاع JWT في نص طلب تسجيل الدخول ، ونريد أيضًا تقديم طلب API منفصل لمعرفة تفاصيل المستخدم مثل معلومات ملفه الشخصي. لذلك دعونا نتجاوز وحدة تحكم جلسة Devise.

غيّر التكوين المبتكر في الطرق. rb ليقول إنك تجاوزت وحدة التحكم وأضفت نقطة نهاية "حالية" إضافية:

ثم دعنا نضيف ملف التحكم هذا ووجهات النظر. إذا كنت تستخدم jbuilder هنا ، فستحتاج إلى إلغاء تثبيت jbuilder في Gemfile ، قم بتشغيل "حزمة الواجهة الخلفية للجذر" ، عامل إعادة التشغيل ، وأعد تشغيل الحاويات مرة أخرى.

جرب هذه الطرق الآن. قم بإجراء POST السابقة وهذه المرة يجب أن يعود الرمز المميز في نص الاستجابة وكذلك الرؤوس.

حاول القيام بـ GET بنقطة النهاية / api / users / الحالية مع رأس "Authorization: Bearer $ token" ورؤية ما إذا كان يمكنك استعادة معرف المستخدم والبريد الإلكتروني.

Woop! آخر شيء واحد: لنجعل ExamplesController يتطلب المصادقة. إضافة إلى وحدة التحكم هذه:

before_action: authenticate_user!

إذا عدت إلى تطبيق الواجهة الأمامية ، فسترى الآن أنه فشل بسبب خطأ 401 غير مصرح به. الوقت لإضافة المصادقة إلى الواجهة الأمامية!

قم بتثبيت مكتبة مصادقة Nuxt:

أعد تشغيل الحاويات الخاصة بك قبل المتابعة لتمكين هذا التكوين الجديد.

لنقم بإنشاء تسجيل دخول إلى صفحة مستخدم. مع عناصر تحكم تسجيل الدخول / الخروج استنادًا إلى الحالة الحالية للمستخدم:

هناك الكثير من الأمور التي تحدث هنا ، لكن يجب أن يكون العمل بها سهلاً بشكل معقول. تستدعي طريقة تسجيل الدخول () الطريقة المكافئة في مكتبة المصادقة ، لتمرير كائن JSON المناسب الذي يتوقعه Devise. إذا كان هناك خطأ ، فإنه يعين الخطأ ، والذي تتم مراقبته بواسطة .

وأخيرًا ، ستحتاج إلى إعادة توجيه المستخدمين إذا لم يتم تسجيل دخولهم. بشكل افتراضي ، تعيد البرامج الوسيطة للمصادقة توجيه المستخدمين لتسجيل الدخول. إذا لم يتم تسجيل الدخول ، لذلك يتعين علينا تمكين البرامج الوسيطة للمصادقة على الفهرس. .vue:

الوسيطة: [المصادقة] ،

قد ترغب أيضًا في إضافة رابط إلى / تسجيل الدخول إلى شريط الأدوات في default.vue. الأمر متروك لك.

جرب الآن تطبيق الواجهة الأمامية مرة أخرى!

تمت إعادة التوجيه إلى صفحة تسجيل الدخول عند تسجيل الخروجولكن أستطيع أن أرى أمثلة بلدي عند تسجيل الدخول!

هذا هو المكان الذي أتركك فيه! إنها في الحقيقة مجرد بداية تكامل المصادقة ، لكن آمل أن ترى أنه ليس هناك قدر كبير من العمل لاستكماله. ستحتاج إلى إضافة تسجيل ، والقيام بأشياء مثل التأكد من أن الرموز المميزة منتهية الصلاحية لا لها الأسبقية على بيانات الاعتماد عند تسجيل الدخول. [تحرير: وافق مشرفو وحدة المصادقة على أنه لا ينبغي إرسال الرموز المميزة منتهية الصلاحية مع طلب تسجيل الدخول ، و @ nuxtjs / auth 4.2.0 يعملان على حل المشكلة.] وثائق المصادقة والتطبيقات التجريبية هي مكان جيد للبدء.

إذا كانت هذه المقالة مفيدة ، فالرجاء مشاركتها حولها ، ورمي بعض التصفيقات ، أو أخبرني كيف تحصل على التعليقات.

تحديث: يمكنك الآن قراءة هذا المتابعة حول كيفية النشر في Heroku!