قوائم التنقل التي تراعي الأذونات تحسّن الوضوح، لكن الأمان يجب أن يُطبَّق على الخادم. اطلع على أنماط بسيطة للأدوار، السياسات، وإخفاء الواجهة بأمان.

عندما يقول الناس "اخفِ الزر"، عادة يقصدون أمرين: تقليل الفوضى للمستخدمين الذين لا يستطيعون استخدام ميزة، أو منع سوء الاستخدام. الهدف الأول هو ما يمكن تحقيقه على الواجهة فقط.\n\nقوائم التنقل المدركة للأذونات هي في الأساس أداة تجربة مستخدم. تساعد شخصًا ما يفتح التطبيق على رؤية ما يمكنه فعله مباشرةً، دون أن يصطدم بشاشات "تم الرفض" عند كل نقرة تقريبًا. كما تقلّل من عبء الدعم عبر منع الالتباس مثل "أين أوافق على الفواتير؟" أو "لماذا تعطي هذه الصفحة خطأً؟"\n\nإخفاء عناصر الواجهة ليس أمانًا. إنه وضوح.
حتى زميل فضولي لا يزال بإمكانه:\n
نهاية جيدة للنهج تبدو هكذا:
مثال: في CRM صغير، يجب أن يرى مندوب المبيعات Leads وTasks، لكن ليس إدارة المستخدمين. إذا لصق عنوان إدارة المستخدمين مع ذلك، يجب أن تفشل الصفحة بأمان، ويجب أن يمنع الخادم أي محاولة لعرض قائمة المستخدمين أو تغيير الأدوار.
الرؤية هي ما تختاره الواجهة للعرض. التفويض هو ما سيسمح به النظام فعليًا عندما يصل الطلب للخادم.
قوائم التنقل المدركة بالأذونات تقلل الالتباس. إذا لم يُسمح لشخص برؤية Billing أو Admin أبدًا، فإخفاء هذه العناصر يحافظ على نظافة التطبيق ويقلل تذاكر الدعم. لكن إخفاء زر ليس قفلًا. لا يزال الناس قادرين على محاولة استدعاء نقطة النهاية الأساسية باستخدام أدوات المطور، أو إشارات مرجعية قديمة، أو طلب منسوخ.
قاعدة عملية: قرِّر الخبرة التي تريدها، ثم نفّذ القاعدة على الخادم مهما فعلت الواجهة.
عندما تقرر كيف تعرض إجراءً ما، تغطي ثلاث أنماط معظم الحالات:
"يمكنك العرض لكن لا التعديل" شائع ويستحق التصميم الصريح. اعتبره إذنين: واحد للقراءة وآخر للتعديل. في القائمة قد تعرض تفاصيل العميل للجميع الذين يملكون حق القراءة، لكن تعرض "تعديل العميل" فقط لمن يملكون حق الكتابة. في الصفحة، اجعل الحقول للقراءة فقط وقم بتقييد أدوات التعديل، مع السماح بتحميل الصفحة.
الأهم من ذلك، الخادم يقرر النتيجة النهائية. حتى لو أخفت الواجهة كل إجراء إداري، يجب أن يفحص الخادم الأذونات على كل طلب حساس ويعيد استجابة واضحة "غير مسموح" عندما يحاول أحدهم.
أسرع طريقة لنشر قوائم تنقل مدركة للأذونات هي البدء بنموذج يمكن لفريقك شرحه في جملة واحدة. إذا لم تستطع شرحه، فلن تحافظ عليه صحيحًا.
استخدم الأدوار للتجميع، ليس للمعنى. Admin وSupport دلاء مفيدة. لكن عندما تبدأ الأدوار بالتكاثر (Admin-West-Coast-ReadOnly)، تصبح الواجهة متاهة ويصبح الخادم تخمينًا.
فضل الأذونات كمصدر للحقيقة لما يمكن للشخص فعله. اجعلها صغيرة ومحددة بالأفعال، مثل invoice.create أو customer.export. هذا يتوسع أفضل من انتشار الأدوار لأن الميزات الجديدة عادة تضيف إجراءات جديدة، وليس مسميات وظيفية جديدة.
ثم أضف السياسات (القواعد) للسياق. هنا تتعامل مع "يمكن التعديل على سجلك فقط" أو "يمكن الموافقة على فواتير فقط أقل من 5,000". السياسات تمنعك من خلق عشرات الأذونات المتشابهة التي تختلف فقط بشرط.
طبقة قابلة للصيانة تبدو هكذا:
التسمية أهم مما يتوقع الناس. إذا قالت الواجهة Export Customers لكن الـ API يستخدم download_all_clients_v2، فسوف تخفي في النهاية الشيء الخطأ أو تمنع الشيء الصحيح. احتفظ بالأسماء بشرية، متسقة، ومشتركة بين الواجهة والخلفية:
noun.verb (أو resource.action) باستمرارمثال: في CRM، قد يتضمن دور المبيعات lead.create وlead.update، لكن سياسة تحدد التحديثات على العملاء التي يملكها المستخدم. هذا يبقي قائمتك واضحة بينما يظل الخادم صارمًا.
قوائم التنقل المدركة بالأذونات تبدو جيدة لأنها تقلل الفوضى وتمنع النقرات العرضية. لكنها تساعد فقط عندما يبقى الخادم هو المتحكم. فكر في الواجهة كدليل، والخادم كقاضي.
ابدأ بكتابة ما تحميه. ليس الصفحات، بل الإجراءات. عرض قائمة العملاء مختلف عن تصدير العملاء وحذف العميل. هذا هو العمود الفقري لقوائم التنقل المدركة التي لا تتحول لمسرحية أمنية.
canEditCustomers، canDeleteCustomers، canExport، أو قائمة مضغوطة من سلاسل الأذونات. اجعلها موجزة.قاعدة صغيرة لكن مهمة: لا تثق بعلامات الدور أو الأذونات المرسلة من العميل. يمكن للواجهة إخفاء الأزرار اعتمادًا على القدرات، لكن واجهة الـ API يجب أن ترفض الطلبات غير المصرح بها.
يجب أن تساعد قوائم التنقل المدركة الأشخاص على إيجاد ما يمكنهم فعله، وليس الادعاء بأنها تفرض الأمان. الواجهة هي درابزين إرشادي. الخادم هو القفل.
بدلًا من نشر فحوصات الأذونات على كل زر، عرّف التنقل من تكوين واحد يتضمّن الإذن المطلوب لكل عنصر، ثم اعرض القوائم من هذا التكوين. هذا يحافظ على قابلية قراءة القواعد ويتجنب فحوصات منسية في زوايا الواجهة.
نمط بسيط يبدو هكذا:
const menu = [
{ label: "Contacts", path: "/contacts", requires: "contacts.read" },
{ label: "Export", action: "contacts.export", requires: "contacts.export" },
{ label: "Admin", path: "/admin", requires: "admin.access" },
];
const visibleMenu = menu.filter(item => userPerms.includes(item.requires));
فضّل إخفاء أقسام كاملة (مثل Admin) بدلًا من نشر الفحوصات على كل رابط صفحة إدارية. هذا أقل أماكن لتنسى شيئًا.
اخفِ العناصر عندما لا يُسمح للمستخدم بها أبدًا. عطّل العناصر عندما يمتلك المستخدم الإذن لكن يفتقر إلى السياق الحالي.
مثال: يجب تعطيل "حذف جهة اتصال" حتى يتم اختيار جهة اتصال. نفس الإذن، لكن لا يوجد سياق كافٍ بعد. عند التعطيل، أضف رسالة قصيرة تشرح السبب (تلميح، نص مساعد، أو ملاحظة داخلية): اختر جهة اتصال للحذف.
مجموعة قواعد تتحمل:
إخفاء عناصر القائمة يساعد الناس على التركيز، لكنه لا يحمي شيئًا. يجب أن يكون الخادم الحكم النهائي لأن الطلبات يمكن إعادة تشغيلها أو تعديلها أو تفعيلها خارج واجهتك.
قاعدة جيدة: كل إجراء يغيّر البيانات يحتاج فحص أذونات واحد، في مكان واحد، يمر به كل طلب. يمكن أن يكون هذا وسطية (middleware)، غلاف معالج، أو طبقة سياسات صغيرة تستدعيها في بداية كل نقطة نهاية. اختر نهجًا واحدًا والتزم به، وإلا ستفوت مسارات.
حافظ على التفويض منفصلًا عن التحقق من صحة المدخلات. قرر أولًا، "هل مسموح لهذا المستخدم بهذا؟"، ثم تحقق من الحمولة. إذا تحققت أولًا، فقد تكشف تفاصيل (مثل وجود معرفات سجلات) لشخص لا ينبغي حتى أن يعرف أن الإجراء ممكن.
نمط يتوسع جيدًا:
Can(user, "invoice.delete", invoice)).استخدم رموز حالة تساعد الواجهة وسجلاتك:
401 Unauthorized عندما لا يكون المتصل مسجلاً.403 Forbidden عندما يكون مسجلاً لكنه غير مسموح.كن حذرًا مع 404 Not Found كتمويه. يمكن أن يكون مفيدًا لتجنب كشف وجود مورد، لكن إذا استخدمته عشوائيًا يصبح استكشاف الأخطاء صعبًا. اختر قاعدة ثابتة لكل نوع مورد.
تأكد أن نفس التفويض يُجرى سواء جاء الإجراء من نقرة زر، تطبيق موبايل، سكربت، أو استدعاء API مباشر.
أخيرًا، سجّل محاولات الرفض للتتبع والمراجعة، لكن احرص على حماية السجلات. سجّل من، أي إجراء، ونوع المورد على مستوى عال. تجنّب الحقول الحساسة أو الحمولات الكاملة أو الأسرار.
معظم أخطاء الأذونات تظهر عندما يفعل المستخدمون شيئًا لم تتوقعه قائمتك. لهذا السبب قوائم التنقل المفيدة لا تكفي إذا لم تصمم أيضًا للمسارات التي تتجاوزها.
إذا أخفت القائمة قسم Billing لدور ما، لا يزال المستخدم قادرًا على لصق عنوان محفوظ أو فتحه من تاريخ المتصفح. عامل كل تحميل صفحة كطلب جديد: احصل على أذونات المستخدم الحالية، واجعل الشاشة نفسها ترفض تحميل البيانات المحمية عندما يفتقد الإذن. رسالة ودودة "ليس لديك صلاحية" جيدة، لكن الحماية الحقيقية أن الخادم لا يعيد شيئًا.
يمكن لأي شخص استدعاء API من أدوات المطور، سكربت، أو عميل آخر. لذا افحص الأذونات على كل نقطة نهاية، ليس فقط شاشات الإدارة. الخطر السهل الإغفال هو الإجراءات الجماعية: نقطة نهاية واحدة /items/bulk-update قد تسمح لغير المسؤول بتغيير حقول لا يرونها في الواجهة.
قد تتغير الأدوار أيضًا أثناء الجلسة. إذا أزال المسؤول إذنًا، قد يبقى لدى المستخدم رمز قديم أو حالة قائمة مخزنة. استخدم رموزًا قصيرة العمر أو بحثًا على الخادم للأذونات، وتعامل مع 401/403 بتحديث القدرات وتحديث الواجهة.
الأجهزة المشتركة تبعث فخًا آخر: حالة القائمة المخزنة قد تتسرب بين الحسابات. خزّن ظهور القائمة مفاتيح بمعرّف المستخدم، أو تجنّب حفظها أصلًا.
خمسة اختبارات تجدر إجراؤها قبل الإطلاق:
تخيل CRM داخلي بثلاثة أدوار: Sales، Support، وAdmin. الجميع يسجل الدخول والتطبيق يعرض قائمة يسارية، لكن القائمة مجرد وسيلة راحة. السلامة الحقيقية هي ما يسمح به الخادم.
ها قائمة أذونات بسيطة تبقى مقروءة:
تبدأ الواجهة بطلب من الخادم إجراءات المستخدم المسموح بها (كقائمة سلاسل الأذونات) بالإضافة إلى سياق أساسي مثل معرّف المستخدم والفريق. تُبنى القائمة من ذلك. إذا لم تكن لديك billing.view، فلن ترى Billing. إذا كان لديك leads.export، سترى زر التصدير في شاشة Leads. إذا كان بإمكانك تعديل Leads التي تملكها فقط، قد يظهر زر Edit لكن يجب أن يكون معطلاً أو يعرض رسالة واضحة عندما لا يكون العميل ملكك.
والجزء المهم: كل نقطة نهاية إجراء تطبق نفس القواعد.
مثال: Sales يمكنه إنشاء Leads وتعديل تلك التي يملكها. Support يمكنه عرض التذاكر وتعيينها، لكنه لا يلمس الفوترة. Admin يدير المستخدمين والفوترة.
عندما يحاول أحدهم حذف Lead، يتحقق الخادم:
leads.delete؟lead.owner_id == user.id؟حتى لو استدعى مستخدم Support نقطة نهاية الحذف يدويًا، يحصل على استجابة ممنوعة. عنصر القائمة المخفي لم يكن الحماية. القرار كان على الخادم.
أكبر فخ هو التفكير أنك انتهيت عندما تبدو القائمة صحيحة. إخفاء الأزرار يقلل الالتباس، لكنه لا يقلل المخاطر.
الأخطاء الأكثر شيوعًا:
role أو isAdmin أو permissions من المتصفح كحقيقة. استخرج الهوية والوصول من جلستك أو رمزك، ثم ابحث عن الأدوار والأذونات من طرف الخادم.مثال ملموس: تخفي قائمة تصدير Leads لغير المدراء. إذا لم يفحص نقطة نهاية التصدير الأذونات أيضًا، يمكن لأي مستخدم يخمن الطلب (أو ينسخه من زميل) تنزيل الملف.
قبل طرح قوائم التنقل المدركة، قم بجولة أخيرة تركز على ما يمكن للمستخدمين فعلاً فعله، لا ما يمكنهم رؤيته.
تجوّل في التطبيق ككل دور رئيسي وجرب مجموعة الإجراءات نفسها. افعل ذلك في الواجهة وأيضًا باستدعاء نقاط النهاية مباشرة (أو باستخدام أدوات المطور) للتأكد أن الخادم هو مصدر الحقيقة.
قائمة التحقق:
طريقة عملية لكشف الفجوات: اختر زرًا "خطيرًا" (حذف مستخدم، تصدير CSV، تغيير الفوترة) وتتبع المسار من البداية للنهاية. يجب أن يكون عنصر القائمة مخفيًا عند اللزوم، ونقطة نهاية الـ API ترفض المكالمات غير المصرح بها، والواجهة تتعافى بلطف عند استلام 403.
ابدأ صغيرًا. لست بحاجة لمصفوفة وصول مثالية في اليوم الأول. اختر مجموعة الإجراءات المهمة (عرض، إنشاء، تعديل، حذف، تصدير، إدارة مستخدمين)، ضعها على الأدوار الموجودة، وتابع.
قبل بناء الشاشات، قم بجولة تخطيطية سريعة تدرج الإجراءات، لا الصفحات. عنصر قائمة مثل Invoices يخفي الكثير من الإجراءات: عرض القائمة، عرض التفاصيل، إنشاء، رد الأموال، تصدير. كتابة هذه الأمور أولًا تجعل الواجهة وقواعد الخادم أوضح، وتمنع الخطأ الشائع المتمثل في تقييد صفحة كاملة بينما تترك نقطة نهاية خطرة غير محمية.
عند إعادة هيكلة قواعد الوصول، عاملها كأي تغيير خطير: احتفظ بشبكة أمان. اللقطات (snapshots) تتيح مقارنة السلوك قبل وبعد. إذا فقد دور حقًا يحتاجه أو اكتسب حقًا لا يجب أن يحصل عليه، فإن التراجع أسرع من تصحيح الإنتاج بينما المستخدمون معطلون.
روتين إصدار بسيط يساعد الفرق على التحرك بسرعة دون التخمين:
إذا كنت تبني بمنصة محادثة مثل Koder.ai (koder.ai)، ينطبق نفس الهيكل: حدّد الأذونات والسياسات مرة واحدة، اجعل الواجهة تقرأ القدرات من الخادم، واجعل فحوصات الخادم غير اختيارية في كل معالج.
قوائم التنقل المدركة للأذونات تحل في الأساس مشكلة الوضوح، لا الأمن. تساعد المستخدمين على التركيز على ما يمكنهم فعلاً فعله، وتقلل النقرات التي تؤدي إلى نهايات مسدودة، وتقلل أسئلة الدعم من نوع "لماذا أرى هذا؟".
يجب أن يُطبَّق الأمن دائمًا على الخادم، لأن أي شخص يمكنه استخدام الروابط العميقة أو الإشارات المحفوظة أو استدعاء API مباشرة بغض النظر عما تظهره الواجهة.
اخفِ العنصر عندما يجب أن يكون غير قابل للاكتشاف فعليًا لدور ما ولا يوجد طريق متوقع لاستخدامه.\n\nعطّل العنصر عندما قد يكون لدى المستخدم صلاحية لكن ينقصه السياق الآن، مثل عدم اختيار سجل، أو حالة نموذج غير صالحة، أو أثناء تحميل البيانات. وإذا عطلت العنصر، أضف تفسيرًا قصيرًا حتى لا يبدو معطلاً.
لأن الرؤية ليست تفويضًا. يمكن للمستخدم لصق عنوان، إعادة استخدام صفحة إدارية محفوظة في الإشارات المرجعية، أو استدعاء API خارج واجهتك.\n\nعامل الواجهة كدليل، واعتمد على الخلفية كحكم نهائي لكل طلب حساس.
يجب أن يعيد الخادم بعد تسجيل الدخول أو تحديث الجلسة حزمة صغيرة من "القدرات" (capabilities) استنادًا إلى فحوصات الأذونات على الخادم. ثم تُعرض القوائم والأزرار في الواجهة بناءً على ذلك.\n\nلا تثق بعلامات يرسلها العميل مثل isAdmin من المتصفح؛ استخرج الصلاحيات من هوية المصادقة على الخادم.
ابدأ بجرد الإجراءات، لا الصفحات. لكل ميزة، افصل العمليات: عرض، إنشاء، تحديث، حذف، تصدير، دعوة، تغييرات الفوترة.\n\nبعد ذلك نفّذ كل إجراء في معالج الخادم (أو الواسطة) قبل أي عمل. اربط القائمة بنفس أسماء الأذونات حتى تظل الواجهة وAPI متطابقتين.
القاعدة العملية: الأدوار عبارة عن دلاء، والأذونات هي مصدر الحقيقة. اجعل الأذونات صغيرة ومبنية على الإجراءات (مثل invoice.create) واربطها بالأدوار.\n\nإذا بدأت الأدوار بالتكاثر لتمثيل شروط (مثل المنطقة أو الملكية)، انقل الشروط إلى سياسات بدلاً من إنشاء متغيرات دور لا نهائية.
استخدم السياسات لقواعد السياق مثل "تعديل السجل الخاص بك فقط" أو "الموافقة على الفواتير تحت حد معين". هذا يحافظ على ثبات قائمة الأذونات بينما يعبر عن قيود العالم الحقيقي.\n\nيُقيّم الخادم السياسة باستخدام سياق المورد (مثل owner ID أو org ID)، وليس افتراضات من الواجهة.
ليست كل قراءات البيانات بحاجة إلى فحص، لكن القراءات التي تكشف عن بيانات حساسة أو تتجاوز الفلترة العادية يجب أن تُقيَّد أيضًا، مثل التصديرات، سجلات التدقيق، رواتب الموظفين، وقوائم المستخدمين الإدارية.\n\nقاعدة جيدة: افحص كل عمليات الكتابة، وافحص القراءات الحساسة أيضًا.
نقاط النهاية الجماعية سهلة النسيان لأنها تغيّر سجلات متعددة أو حقولًا في طلب واحد. قد يكون المستخدم محجوبًا في الواجهة لكنه يستدعي /items/bulk-update مباشرة.\n\nفحص الأذونات يجب أن يشمل إجراء الدُفعات نفسه، وفحص الحقول المسموح بتغييرها لذلك الدور، وإلا فقد تسمح بتعديل حقول مخفية.
افترض أن الأذونات قد تتغير أثناء جلسة تسجيل الدخول. عند استقبال 401 أو 403، على الواجهة التعامل مع ذلك كحالة طبيعية: حدّث القدرات، حدّث القائمة، وأظهر رسالة واضحة.\n\nتجنب حفظ حالة ظهور القوائم بطريقة يمكن أن تتسرب عبر الحسابات على أجهزة مشتركة؛ إذا خزنتها، فاجعلها مرتبطة بمعرّف المستخدم أو لا تُخزن على الإطلاق.