متابعة من Future Social Authentication Improvements…
نحن الآن في مرحلة نقل جميع معلومات “الحسابات المرتبطة” إلى جدول قاعدة بيانات واحد. سيساعد هذا في تقليل المنطق المكرر بشكل كبير، ويتيح تطويراً أسرع في المستقبل. على سبيل المثال، ترحيل منطق تويتر الأساسي إلى النظام الجديد قلل عدد أسطر الكود من 136 إلى 24 فقط
.
لا يُصمَّم هذا المنشور ليكون دليلاً تعليمياً خطوة بخطوة لإضافة مزوّد مصادقة جديد، بل يهدف إلى تقديم نظرة عامة، مع الإشارة إلى الكود المصدري ذي الصلة عند الحاجة.
تنفيذ المصادق (Authenticator)
يجب على كل مصادق (Authenticator) أن يطبّق فئة فرعية من Auth::Authenticator. لاستخدام المنطق المشترك الجديد، يمكن للمصادق بدلاً من ذلك أن يوسّع Auth::ManagedAuthenticator. يمكن العثور على مثال لتنفيذ بسيط في مصادق فيسبوك الأساسي:
يجب تجاوز name و register_middleware في الفئات المنفذة، بالإضافة إلى enable_setting — وهو إعداد الموقع المنطقي الذي يستخدمه المسؤول لتفعيل المزوّد.
يجب أيضاً على المصادق أن يصرّح بـ required_settings: وهي إعدادات الموقع التي يجب أن تحتوي على قيمة قبل أن تنجح عملية المصادقة. تستخدم الفئة الأساسية هذه الإعدادات لـ configured?، و enabled? هي enable_setting && configured?، لذا فإن المزوّد الذي تفتقد بياناته الاعتمادية لن يُعلن أبداً في صفحة تسجيل الدخول ويبقى مساره /auth/<name> مغلقاً — وإلا فإن النقر على الزر سيترك المستخدم عالقا في صفحة خطأ المزوّد الخاصة به دون طريق للعودة. كما يسمح التصريح بـ required_settings لـ AuthProviderCredentialsValidator برفض تفعيل المزوّد من الأساس؛ قم بتوصيله باستخدام validator: "AuthProviderCredentialsValidator" على إعداد التفعيل.
def enable_setting
:enable_google_oauth2_logins
end
def required_settings
%i[google_oauth2_client_id google_oauth2_client_secret]
end
المصادق الذي يتجاوز enabled? مباشرة يختار الخروج من كلا البوابتين.
هامش: لتوافق تعدد المواقع (multisite)، من المهم أن تُوفَّر أي معلومات خاصة بالموقع إلى omniauth في دالة
setup(lambda)، بدلاً من تثبيتها في وقت التعريف. راجع جميع المصادقات الأساسية كمثال على ذلك.
تُعالج جميع المنطق لربط الحسابات الخارجية بحسابات Discourse بواسطة Auth::ManagedAuthenticator. يعتمد هذا على عودة مزوّد omniauth بالبيانات بالصيغة المحددة في توثيقهم. إذا كانت هناك حاجة إلى أي معالجة لهذه البيانات، يمكن للمصادقات تجاوز طريقة after_authenticate ومعالجة auth_token كما هو مطلوب. على سبيل المثال، يزيل مصادق تويتر الأساسي جميع معلومات extra من الرمز:
تُخزَّن البيانات في جدول قاعدة البيانات user_associated_accounts. يتم أخذ provider_uid و info و credentials و extra مباشرة من البيانات التي يعيدها omniauth.
تُحمَّل صور المزوّد من info.image عند المصادقة وتُحفظ في avatar_upload_id لكل حساب. تبقى هذه الصور منفصلة عن الصورة المرفوعة من المستخدم والإعدادات المسبقة القابلة للاختيار. يعرض منتقي الصور (Avatar Picker) الصور المخزنة مؤقتاً من المزوّدات المفعّلة تحت أذونات الصورة الرمزية الحالية.
تملك UserAvatar استيراد الصور الرمزية، واختيارها، وتحديثها، والتنظيف. يجدول المصادق استرداد المزوّد من خلال UserAvatar.retrieve_for_associated_account؛ وتستخدم مهام التنزيل والمستوردين UserAvatar.import_url_for_user مع تمرير associated_account_id لصور المزوّد. تفوّض طرق الراحة للمستخدم ومكالمات دورة حياة الحساب/الرفع تغييرات الصورة الرمزية إلى UserAvatar؛ وتبقى الأذونات في Guardian.
يسجّل user_avatars.selected_user_associated_account_id مزوّدًا تم اختياره صراحةً. تحدّث التنزيلات اللاحقة الصورة الرمزية المعروضة فقط طالما بقي ذلك المزوّد مختاراً. تختار الحسابات الجديدة مزوّداتها في البداية عندما لم تُسند صورة رمزية؛ وتواصل auth_overrides_avatar في فرض اختيار المزوّد. تحتفظ الصور الرمزية الحالية بمظهرها ولا يُسند لها مزوّد تلقائياً. تملأ الحسابات المرتبطة الحالية خيارات مزوّداتها عند تسجيل الدخول التالي.
اختيار صورة رمزية أخرى يمسح اختيار المزوّد. يحافظ فصل الحساب على صورته المعروضة حالياً كنسخة محلية (snapshot) ويحافظ على أي صورة مرفوعة منفصلة. تحتفظ التنزيلات الفاشلة بالصورة السابقة. تُتجاهل التنزيلات المجدولة إذا تم فصل الحساب، أو نقله إلى مستخدم آخر، أو إذا أصبح يوفر الآن عنوان URL مختلفاً للصورة.
لا يزال اختيار Gravatar يستخدم مطابقة معرف الرفع (upload-ID). لذلك، يمكن لصورة مخصصة أو مسبقة مطابقة لـ Gravatar المخزنة مؤقتاً أن تتبع تحديثات Gravatar اللاحقة.
بمجرد تعريف فئة Authenticator، تحتاج إلى تسجيلها. يجب أن يحدث هذا في وقت مبكر من دورة حياة التطبيق، ولا يمكن أن يحدث داخل طريقة after_initialize في إضافة (plugin). يمكن أن يحتوي التسجيل الأدنى ببساطة على مرجع إلى المصادق. في الإضافة، يمكن إجراء التسجيل باستخدام دالة auth_provider. على سبيل المثال:
auth_provider authenticator: OpenIDConnectAuthenticator.new()
في النواة (core)، يتم التسجيل في discourse.rb. يمكن العثور على قائمة كاملة بخيارات AuthProvider الممكنة هنا. يمكن تعريف المحتوى النصي باستخدام هذه الخيارات، لكن من الأفضل توفير نصوص قابلة للترجمة في client.en.yml متبعةً المفاتيح القياسية. على سبيل المثال:
ملاحظات إضافية حول ManagedAuthenticator بواسطة @fantasticfears
تفاصيل ManagedAuthenticator
قد تحتاج إلى العمل على شيء خاص للمصادقة. وتريد معرفة المزيد حول ManagedAuthenticator. في الأساس، لديها عدة عمليات وخيارات، وتتحكم في كيفية استخدام البيانات.
يدير Discourse معلومات المستخدمين من خلال متحكمين (controllers). يدير Users::OmniauthCallbacksController الحمولة (payload) بمجرد اكتمال مصادقة OAuth2. تُستدعى after_authenticate هنا. كما تُستخدم can_connect_existing_user? هنا.
هناك بعض الطرق الخاصة (private methods) يمكنك قراءتها لفهم كيفية عمل حقول البيانات المختلفة.
if authenticator.can_connect_existing_user? && current_user
@auth_result = authenticator.after_authenticate(auth, existing_account: current_user)
else
@auth_result = authenticator.after_authenticate(auth)
end
يحتوي UsersController على revoke_account الذي يستخدم can_revoke? و revoke. لكن لكي تعمل طريقة revoke عن بُعد، تحتاج إلى بناء تطبيقك الخاص.
UserAuthenticator هي فئة خدمة تساعد في مصادقة (تحقق تأكيد البريد الإلكتروني أو مسار OAuth2) المستخدمين. تُستدعى after_create_account هنا.
يبقى المنطق الأساسي في after_authenticate مع فئة البيانات Auth::Result. نتبع بنية البيانات هنا. سيتم تمرير extra_data إلى after_create_account لإنشاء السجلات ذات الصلة.
result.extra_data = {
provider: auth_token[:provider],
uid: auth_token[:uid],
info: auth_token[:info],
extra: auth_token[:extra],
credentials: auth_token[:credentials]
}
سيتيح محاولة المطابقة والربط بحساب موجود.
قد تتساءل لماذا من الممكن إنشاء الحساب تلقائياً لكن لا يوجد User.create. يتم هذا في UsersController#create.
authentication = UserAuthenticator.new(user, session)
المستخدم هو نسخة جديدة (fresh instance) ستُملأ ببيانات الجلسة التي يجهزها مزوّد المصادقة. ثق بي، إنها مجرد سحر.
الترحيل إلى النظام الجديد
لتوفير انتقال سلس إلى النظام الجديد، يجب ترحيل البيانات من موقع التخزين القديم. لمزوّدات المصادقة الأساسية، قد تكون هذه جداول مخصصة. للإضافات، قد تكون plugin_store_rows، أو oauth2_user_infos. البيانات الدنيا المطلوبة في صف user_associated_accounts هي provider_name و provider_uid و user_id. لمثال على الترحيل راجع:
بمجرد إطلاق نظام ManagedAuthenticator إلى الفرع المستقر مع الإصدار v2.2.0، سنبدأ في ترحيل إضافات المصادقة الرسمية. في هذه المرحلة، سيتم إضافة مثال على ترحيل plugin_store_row هنا.
هذا المستند مُدار بالإصدارات - اقترح تغييرات على github.