الجلسات والأمان

جلسات المستند والتحكم في الوصول

رمز Doconut قوي: أي شخص يقدمه يمكنه طلب كل صفحة من المستند إذا لم يكن مرتبطًا بجلسة الفتح. تشرح هذه الصفحة ما تحتويه الجلسة، مدة عمرها، والفحوصات التي يفعّلها UseDoconut() افتراضيًا.

ما تحتويه جلسة المستند

كل OpenDocumentAsync ناجح ينشئ جلسة واحدة في IMemoryCache:

  • عارض الصيغة المحملة (مثيل محرك المستند الذي يحتفظ بالمستند المحلل)،
  • حالة كل صفحة — الدوران، الانعكاسات، وبيانات التعليقات التي يطبقها المستخدم في الواجهة،
  • فهرس البحث الاختياري، يُبنى ببطء عند أول بحث (أو يُحمَّل من ملف .srh مُسبق الإنشاء عندما تُقدم الصفحات من تخزين مشترك)،
  • الجلسة العلامة المائية من DocOptions.Watermark.

عمر الجلسة

تنتهي صلاحية الجلسات على نافذة منزلقة: DocOptions.TimeOut دقيقة (الافتراضي 60)، تُعاد الضبط بكل طلب يقدم الرمز. عندما تُطرد جلسة — إما بانتهاء صلاحيتها أو عبر CloseDocument(token) — يستدعي رد النداء الخاص بالطرد إغلاق محرك المستند وتحرير الذاكرة المرتبطة فورًا.

csharp
// جلسة قصيرة الأمد لمعاينة لمرة واحدة
var token = await viewer.OpenDocumentAsync(path, new DocOptions { TimeOut = 10 });

طلب يحمل رمزًا منتهي الصلاحية يحصل على صورة خطأ تقول Document session not found. Please re-open document. — يجب على العميل إعادة الفتح للحصول على رمز جديد.

ربط الرموز المدمج

مع UnsafeMode = false (الإعداد الافتراضي)، يربط OpenDocumentAsync الرمز الجديد بـ جلسة ASP.NET لطلب HTTP الذي فتحه، بكتابة علامة secure-{token} في تلك الجلسة. ثم يرفض وسطية Doconut خدمة الصفحات لأي جلسة متصفح أخرى:

  • متصفح/جلسة مختلفة تقدم رمزًا مسروقًا → صورة خطأ You Are Not Authorized To View This Page.
  • وسطية الجلسة غير مسجلة → HTTP 500 Session middleware not configured. Call UseSession() before UseDoconut().

هذا هو السبب في إصرار الدليل السريع على AddSession() + app.UseSession() قبل فرع Doconut. نتيجتان عمليتان:

  • يجب على العميل إرسال ملف تعريف الارتباط لجلسة ASP.NET مع طلبات الصفحات. إعدادات عبر الأصل التي تزيل ملفات تعريف الارتباط (أو عميل API بدون مخزن ملفات تعريف الارتباط) سيفشل الفحص — هذه ميزة تعمل، ليست خطأ.
  • options.UnsafeMode = true يعطل الربط تمامًا. هو موجود لسيناريوهات مُتحكم فيها؛ اتركه false في الإنتاج على عقدة واحدة.

لاحظ التهجئة. المكتبة السابقة لـ .NET Standard كانت تسمّي هذه الخاصية UnSafeMode وتم تمريرها إلى الوسطية؛ هنا هي UnsafeMode وتُضبط مرة واحدة داخل AddDoconut().

ربط الرموز يتحكم فيه فقط المفتاح العالمي UnsafeMode — هو مفعَّل افتراضيًا (UnsafeMode = false) ويُطبق على كل جلسة. لا يوجد خيار استثناء لكل مستند؛ ضبط UnsafeMode = true يعطل الربط عالميًا.

منح الوصول والمستخدمين المصادق عليهم

عند كون UnsafeMode هو false، يدرج UseDoconut() وسطية وصول المستند تلقائيًا قبل وسطية الصفحة. لا تسجِّله مرة ثانية. عندما يحمل الطلب رمزًا، يبحث عن منح الوصول المسجَّل عند فتح المستند ويصرّح فقط إذا تحققت كل ما يلي:

  1. وجود منح للرمز،
  2. لم تنتهِ صلاحيته (مدة المنح = TimeOut للمستند)،
  3. معرف جلسة ASP.NET المطلوب يطابق الذي فتح المستند،
  4. إذا كان الفاتح مُصادقًا، فإن مطالبة NameIdentifier للمستخدم المطلوب تتطابق أيضًا.

تُعيد الفشل 403 — كصورة PNG للخطأ لطلبات الصفحة/الصورة المصغرة، كنص عادي خلاف ذلك. الرسالة ومفتاح استعلام الرمز يأتيان من DocumentSecurityOptions (TokenQueryKey، الافتراضي "token"؛ UnauthorizedMessage، الافتراضي "You Are Not Authorized To View This Page."). اضبط هذه الخيارات عبر DI في ASP.NET Core قبل بناء التطبيق. إذا كانت حالة الجلسة غير متوفرة، تفشل الوسطية مغلقةً مع HTTP 500: ASP.NET Session is required for Doconut document security.

csharp
builder.Services.Configure<Doconut.Security.DocumentSecurityOptions>(options =>
{
    options.TokenQueryKey = "token";
    options.UnauthorizedMessage = "You Are Not Authorized To View This Page.";
});

ثم تتحقق وسطية الصفحة الأساسية من علامة الجلسة secure-{token} قبل أن تخدم المستند. مع UnsafeMode = true، يتخطى UseDoconut() وسطية الوصول وتُعطَّل أيضًا فحص العلامة الأساسية.

الأمان عبر عدة عقد

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

الإجابة ليست ترك المستندات غير محمية. استخدم تذاكر وصول موقعة عبر AddDoconutDistributedDocumentSecurity(...)، التي تستبدل فحص الجلسة ببيان يمكن لكل عقدة التحقق منه بشكل مستقل. الترتيب الكامل موجود في النشر الموزع.

إلغاء الترخيص

CloseDocument(token) لا يحرّر الذاكرة فقط — بل يزيل أيضًا علامة secure-{token} ويلغي منح الوصول، لذا يصبح الرمز المغلق ميتًا على طبقتي الأمان فورًا.

قائمة التحقق للإنتاج

  • احتفظ بـ UnsafeMode = false (الإعداد الافتراضي) على عقدة واحدة — هذا المفتاح العالمي هو ما يربط الرموز بالجلسات.
  • سجِّل AddDistributedMemoryCache() (تطبيقات MVC و Razor Pages لديها بالفعل) و AddSession()، واستدعِ app.UseSession() قبل فرع وسطية Doconut.
  • تأكد من أن سياسة ملف تعريف الارتباط للجلسة تسمح لطلبات الواجهة بحمل الملف (SameSite، HTTPS).
  • استخدم CloseDocument عندما يغادر المستخدم المستند — الذاكرة والأمان يستفيدان.
  • لا تُسجِّل أو تُشارك الرموز أبدًا؛ اعتبرها أوراق اعتماد قصيرة الأمد.
  • هل تُقدِّم من تخزين مشترك؟ انتقل إلى تذاكر وصول موقعة بدلاً من قبول مستندات غير محمية.

هل كانت هذه الصفحة مفيدة؟