دورة_حياة_رمز_Open_API
Open_API_الخاصة_بـ_cTrader_يسمح_ب رمز_وصول_صالح_واحد_لكل_معرف_cTrader_(cID)_في_كل_مرة.في_لحظة إصدار_رمز_جديد_—تجديد_مجدول،أو_إعادة_تفويض_عندما_يربط_المستخدم_حساباً_آخر على_نفس_cID—يتم_إلغاء_صلاحية_رمز_الوصول_السابق.محرك_النسخ_الذي_يعمل على_عقدة_بعيدة_يمسك_ذلك_الرمز_الآن_الميت،لذا_يجب_أن_يصل الرمز_الجديد_إليه_دون_قطع_الاتصال_المباشر.
النموذج
OpenApiAuthorizationهو_المجموع_الذي_يمسك_رموز_الوصول_المشفرة_والتجديد_ ل_cID.فهرس_فريد_على(UserId,_CtidUserId)يفرض **بالضبط_تفويض_واحد_لكل_cID لكل_مستخدم**.TokenVersion—عداد_رتبي_يزداد_كل_مرة_يدور_الرمز(Refresh()، والذي_يغطي_أيضاً_مسار_إعادة_Auth_عند_ربط_حساب_آخر_على_نفس_cID).إنه_علامة الإصدار_لقاعدة_الرمز_الصالح_الواحد_وهو_ما_يستخدمه_المضيف_القيد_التشغيل لاكتشاف_التغيير_حتى_لو_اصطدام_سلسلتين_مما_الرمز.- الرموز_مُشفرة_عند_الـ_rest_عبر_
ISecretProtector(EncryptionPurposes.OpenApiAccessToken/OpenApiRefreshToken)._لا_تُسجل_أبداً_ولاتُخزّن_بنص_صريح.
الانتشار_(تبديل_سلس_في_المكان)
- يدور_الرمز_→الرمز_الجديد+_
TokenVersion_المُزاد_يُPersistence. - المنشئ_
CopyEngineSupervisorعلى_العقدة_المُستضيفة_يعيد_قراءة_الخطة_كل دورة_مصادقة_ويحسب توقيع_الرمز (رموز_الوصول_+_الإصدارات).التغيير يعني_تدويراً. - بدلاً_من_تفكيك_المضيف_إعادة_التشغيل_(الذي_سيقطع_تدفق_تنفيذ_الماستر)_، المنشئ يدفع_الرمز_الجديد_إلى_المضيف_القيد_التشغيل.
- المضيف_يُعيد_المصادقة_على_الحساب_المتأثر على_المقبس_القائم
(
ProtoOAAccountAuthReq_مرة_أخرى)عبرSwapAccessTokenAsync،ثم_يُجري مصادقة_خفيفية._الرمز_القديم_يموت؛_تدفق_النسخ_لا_يتوقف_أبداً.
هذا_ما_يجعل_حالة_cross-cID_آمنة:مستخدم_يضيف_حساباً_ثانياً_من نفس_cID_في_منتصف_التشغيل_يُلغي_صلاحية_الرمز_القديم،وبرنامج النسخ_القيد_التشغيل_يستمر_على_الجديد.
التجديد
OpenApiTokenRefreshService (خلفية)تُجدد_التفويضات_استباقياً_قبل
انتهاء_الصلاحية؛_OpenApiAuthorization.IsExpiring(threshold,_now) يُحرسها.cTrader
يدوّر_رمز التجديد _عند_كل_تجديد،لذا_رمز_التجديد_الجديد_يُPersistence
فوراً؛ذاكرة_التخزين_المقروءة_فقط_التي_لا_تستطيع_الإلحاق_ستُلغي_نفسها
(ذو_صلة_بوظيفة_الاختبار_في_العنقود،التي_ت mount_نسخة_قابلة_للكتابة
من_السر).
تصعيد_الفشل
الفشل_المُجدد_ليس_صامتاً.OpenApiAuthorization.MarkRefreshFailed(reason,_now,_criticalWindow)
يُسجل_RefreshFailedAt،يزيدConsecutiveRefreshFailures،وبرفع
دائماً AccessTokenRefreshFailed (تحذير).عندما_الرمز_الآن_ضمن
App:OpenApi:TokenRefreshCriticalWindow(الافتراضي_6س)من_انتهاء_الصلاحية
والتجديد_لا_يزال_فاشلاً،يُصعد مرة_واحدة بحدث_مجال
AccessTokenRefreshCritical+سجلCriticalلذا_المالك_يمكنه
إعادة_التفويض_قبل_فقدان_عمليات_النسخ/prop-firm_للرمز.عداد_الفشل
ومزلاج_التصعيد_يُعاد_ضبطه_عند_النجاح_التالي_لـ_Refresh.الخدمة
تستمر_في_إعادة_المحاولة_كل_TokenRefreshInterval،لذا_انقطاع_المزود/الصيانة
يشفّي_ذاته_عند_عودة_نقطة_الوصول_التجديد.
تنبيه_إلغاء_الصلاحية_و_الاسترداد_التلقائي_(M1)
إعادة_التفويض_الجزئية/المُعادة_على_cID_تُلغي_صلاحية_الرمز_الذي_
يمسكه_مضيف_النسخ_القيد_التشغيل.عندما_يستدعاء_التداول_يرفض
بـ OpenApiErrorKind.TokenInvalid،المضيف_يرفع_تنبيهاً_مميزاً
CopyTokenInvalidated (سجل_1078)—وليس_فشلاً_عاماً—لذا
قناة_التنبيه_تعرف_أن_رمزاً_يحتاج_انتباهاً.الاسترداد_تلقائي:المنشئ
يعيد_قراءة_التفويض_كل_دورة_وعندما_يتغير_توقيع_الرمز_المُجدد
يدفعه_إلى_المضيف_القيد_التشغيل_لـ تبديل_في_المكان —النسخ_يستأنف
دون_إعادة_إضافة_يدوية.برنامجNotLinkable(رمز/auth_مؤقتاً_غير_
قابل_للحل)كذلك_يُعاد_تقييمه_كل_دورة_منشئ_ويُستضاف_في_لحظة
خطة_تبني_مجدداً.
ساعة_حيوية_المضيف_(M2)
المنشئ_يراقب_مهمة_التشغيل_لكل_ملف_مُستضاف.إذا_خرج_المضيف
или_عطل_بينما_ملفه_لا_يزال_مُخصص_لهذه_العقدة،الساعة_تُلغي
و تُعيد_تشغيله في_الدورة_التالية(سجل_CopyHostRestarted)_
،لذا_مضيف_عالق_يشفّي_ذاته_بدلاً_من_الحاجة_إلى_إعادة_تشغيل_يدوية
—وفشل_ملف_واحد_لا_يعرقل_الآخرين_أبداً(عزل_لكل_ملف).
الاختبارات
- وحدة —
TokenVersionيزداد_علىRefresh؛المضيف_يُجري_تبديلاً في_المكان_بدون_إعادة_تشغيل؛إلغاء_صلاحية_cross-cID_يبدّل_رموز المصدر_والوجهة؛ رمز_وجهة_ملغى_يرفع_CopyTokenInvalidated_ ويسترد_تلقائياً_عند_دفع_الرمز_التالي (M1)؛قرار_الساعةIsHostDeadيعيد_تشغيل_مضيف_مكتمل/معطل_ويترك_ملف_مُعاد_خصيصه وحده(M2). - تكامل —_
TokenVersionيستمر+يزداد_عبر_EF_على_Postgres_الحقيقي؛ توقيع_الرمز_يتغير_عند_زيادة_الإصدار_حتى_لو_السلسلة_لم_تتغير.