← All posts

مغادرة Duende ذاتية الاستضافة: ما الذي يُرحَّل، وما الذي تتوقف عن تشغيله

Authagonal·June 18, 2026
duendeidentityserverdotnetoidcmigration

إن Duende IdentityServer برنامج جيد حقًا: فإذا أردت أن تملك طبقة الهوية لديك من البداية إلى النهاية، فهو المعيار في عالم .NET. لكن "امتلاكه" هو التكلفة بأكملها: أنت تستضيفه، وتُحدِّثه أمنيًا، وتوسّع نطاقه، وتبني كل شيء حوله: واجهة الإدارة، وMFA، وسجلات التدقيق، والعلامة التجارية، وصفحة الحالة، وإدارة المستخدمين والأدوار. وفي مرحلة ما يقرر الفريق أنه يفضّل ألا يشغّل IdP، ويصبح السؤال الوحيد المهم هو مدى صعوبة الانتقال. وإليك ما الذي يُرحَّل فعليًا.

ما الذي تشغّله فعليًا

تجعلك استضافة Duende ذاتيًا مسؤولًا عن أكثر من مجرد نقاط نهاية الرموز:

  • الـ IdP نفسه: الاستضافة، والتوسّع، والتحديثات الأمنية، والترخيص (وSAML إضافة مدفوعة فوق ذلك).
  • كل ما بنيته بنفسك حوله: بوابة الإدارة، وتسجيل MFA، وتسجيل التدقيق، والعلامة التجارية المخصصة، وصفحة الحالة، وإدارة المستخدمين والأدوار.

وهذه القائمة الثانية هي عادةً حيث يذهب الوقت الحقيقي.

ما الذي يُرحَّل، وهو في معظمه آلي

يحتفظ Duende بإعداداته في SQL (في ConfigurationDb) وبمستخدميه في ASP.NET Identity. وعملية الترحيل تقرأ كليهما:

  • العملاء (Clients) ← عملاء OAuth، بما في ذلك عناوين redirect وlogout، وأصول CORS، وأنواع المنح، ودلالات استخدام رموز التحديث وانتهاء صلاحيتها، ومدد صلاحية device-code. العملاء المعطّلون يُستوردون معطّلين، والأسرار منتهية الصلاحية تُتخطى مع تحذير.
  • النطاقات (Scopes) ← تُربط ApiScopes وIdentityResources مباشرةً. أما طبقة ApiResource الوسطى في Duende (وهي جمهور audience مع قائمة مطالبات claims مشتركة) فتُسطَّح إلى النموذج الأبسط: يصبح اسم المورد جمهورًا audience على كل عميل يستخدم نطاقًا عضوًا فيه، وتُدمج مطالباته في تلك النطاقات.
  • المستخدمون ← الخبر السار: قيم تجزئة كلمات المرور في ASP.NET Identity V3 (وكذلك bcrypt القديمة) يجري التحقق منها أصلًا وإعادة تجزئتها عند أول تسجيل دخول. لا إعادة تعيين لكلمات المرور، ولا تذاكر دعم، ولا شيء يلاحظه مستخدموك. (وهذا هو الجزء الصعب فعلًا عند مغادرة Auth0، أما مع Duende فيعمل ببساطة، لأنها التجزئة نفسها التي يستخدمها تطبيقك بالفعل.)
  • الأدوار والتعيينات، وعمليات تسجيل الدخول الخارجية، وموفّرو هوية OIDC كلها تُنقل. أما موفّرو SAML فيُوضع لهم علامة لتعيد ضبطهم في الطرف الآخر.

جزء استقرار الهوية

كما هو الحال في أي انتقال بين موفّري IdP، فإن الأمر الذي يجب ضبطه بدقة هو عدم تغيير sub المستخدم أو client_id: فرموز التحديث في المنبع، وصفوف SCIM في موفّري IdP لدى العملاء، ومعرّفات المستخدمين المخزّنة في قاعدة بياناتك الخاصة، كلها تشير إليهما. وأداة الاستيراد تحافظ على كليهما. وإذا كان أحد مالكي بوابتك موجودًا أيضًا كمستخدم في Duende بمعرّف مختلف، فإنها توفّق بينهما (بالتدوير إلى sub الخاص بـ Duende) عبر خطوات مرحلية قابلة للاسترجاع، بدلًا من ترك مالك نصف مُرحَّل لا يستطيع تسجيل الدخول.

استطراد حول اختبار عمليات الترحيل (مَزلق في .NET)

نحن نختبر أداة الاستيراد مقابل قاعدة بيانات Duende حقيقية ومزروعة بالبيانات، لا مقابل محاكاة mocks، وقد آتى ذلك ثماره. يخزّن ASP.NET Identity حقل AspNetUsers.LockoutEnd بنوع datetimeoffset، وقراءته باستخدام reader.GetDateTime() تُطلق استثناء InvalidCastException على هذا النوع. وبالتالي فإن مستخدمًا واحدًا مقفلًا كان سيُفشل عملية استيراد المستخدمين بأكملها. ولا تكتشف ذلك إلا بتشغيل أداة الاستيراد مقابل بيانات حقيقية تحتوي على مستخدم مقفل بداخلها. وإذا كنت توازن بين أي أداة ترحيل، فهذا هو السؤال الجدير بالطرح: هل اختُبرت مقابل قاعدة بيانات ممتلئة بالبيانات، أم مجرد محاكاة مقابل API المصدر؟

ما الذي تتوقف عن فعله

ليست النقطة في الانتقال هي عملية الترحيل، بل كل ما يأتي بعدها. فـ SAML وSCIM وMFA وسجلات التدقيق والنطاقات المخصصة والعلامة التجارية كلها مُضمَّنة بدلًا من أن تكون أشياء تبنيها وتشغّلها، ويكفّ تحديث IdP وتوسيع نطاقه أمنيًا عن أن يكونا مشكلتك. وإذا كانت استضافة Duende ذاتيًا قرارًا مدروسًا بصيغة "نريد التحكم الكامل" وما زال كذلك، فابقَ عليه: فهذا خيار جيد تمامًا. أما هذا المقال فهو لما يصبح تشغيل IdP ليس المكان الذي تريد أن تنفق فيه وقتك.

إن كنت تفكّر في ذلك

عملية الترحيل آلية في معظمها، وكلمات المرور تُنقل دون عمليات إعادة تعيين، والمعاينة للقراءة فقط: وجّهها نحو قاعدة بيانات Duende لديك فتعرض لك بالضبط ما الذي سيُستورد قبل أن يُكتب أي شيء.

انتقل من Duende