سؤال

أقوم ببناء موقع مجتمعي في Rails لأعضاء منظمة في العالم الحقيقي.أحاول الالتزام بأفضل ممارسات تصميم RESTful، ومعظمها يتم اتباعه بشكل أو بآخر.المشكلة التي تجعل عقلي يعمل في دوائر RESTful الأنيقة هي مسألة التفويض. المصادقة هي مشكلة سهلة تم حلها منذ فترة طويلة مع حلول RESTful المقبولة على نطاق واسع، ولكن يبدو أن ترخيص RESTful هو نوع من الفن الأسود.أحاول العثور على النهج الذي سيوفر الإطار الأكثر عمومية ومرونة للتحكم في الوصول إلى الموارد مع أن يكون بسيطًا قدر الإمكان، وكل ذلك مع التوافق مع بنية RESTful.(أيضا، المهر.)

الاعتبارات:

  1. أحتاج إلى التحكم في الوصول إلى مجموعة متنوعة من الموارد، مثل المستخدمين والصفحات والمشاركات وما إلى ذلك.
  2. يجب أن يكون الترخيص لمورد معين أكثر دقة من CRUD البسيط.
  3. أرغب في السماح لنفسي وللآخرين بتحرير قواعد التفويض من داخل التطبيق.
  4. يجب السماح لقواعد التفويض بالاعتماد على المسندات، مثل (من الناحية المفاهيمية) المالك (المستخدم، المورد) أو مغلق (الموضوع)

الاعتبار (2) هو الذي يهمني أكثر.يبدو أن هناك عدم تطابق في المعاوقة بين تصوري للأذونات ومفهوم RESTful للإجراءات.على سبيل المثال، خذ المشاركات (كما هو الحال في لوحة الرسائل).يفرض REST وجود أربع عمليات على مورد Post:إنشاء وقراءة وتحديث وحذف.من السهل أن نقول إن المستخدم يجب أن يكون قادرًا على تحديث منشوراته الخاصة، ولكن يجب السماح فقط لمستخدمين معينين (أو أدوار أو مجموعات) بقفلها.الطريقة التقليدية لتمثيل القفل تكون ضمن حالة المنشور، ولكن هذا يؤدي إلى الرائحة التي قد يتمكن أو لا يتمكن المستخدم في ظل نفس الظروف من تحديث منشور اعتمادًا على القيم (الصالحة تمامًا) التي يقدمها.يبدو واضحًا بالنسبة لي أن هناك بالفعل إجراءين مختلفين لتغيير حالة البريد، وأن تقليدهما هو مجرد إخفاء انتهاك لمبادئ RESTful.

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

أليس التحلل كلمة أخرى للتعفن؟

يمكن التغلب على ذلك عن طريق تحليل المنشور:يعد القفل مصدرًا فرعيًا لمنشور معين، ولإنشاءه أو تدميره قد يكون لديك أذونات منفصلة.يحتوي هذا الحل على REST، ولكنه يجلب معه صعوبات نظرية وعملية.إذا قمت بتحليل الأقفال، فماذا عن السمات الأخرى؟لنفترض أنني قررت، في نوبة نزوة، أنه يجب السماح فقط لعضو من المديرين بتعديل عنوان المنشور؟إن التغيير البسيط في الترخيص يتطلب إعادة هيكلة قاعدة البيانات لاستيعابه!هذا ليس حلا كبيرا.إن السماح بهذا النوع من المرونة في ظل استراتيجية التحلل يتطلب أن تكون كل سمة موردًا.وهذا يمثل قليلا من المعضلة.كان افتراضي الضمني هو أن المورد يتم تمثيله في قاعدة البيانات كجدول.في ظل هذا الافتراض، يعني المورد لكل سمة جدولًا لكل سمة.ومن الواضح أن هذا ليس عمليا.ومع ذلك، فإن إزالة هذا الافتراض يمثل عدم تطابق في المعاوقة بين الجداول والموارد، مما قد يؤدي إلى فتح علبة من الديدان الخاصة بها.إن استخدام هذا النهج يتطلب دراسة متعمقة أكثر بكثير مما قدمته.لسبب واحد، يتوقع المستخدمون بشكل معقول أن يكونوا قادرين على تحرير سمات متعددة في وقت واحد.أين يذهب الطلب؟إلى أصغر مورد يحتوي على كافة السمات؟إلى كل الموارد الفردية بالتوازي؟إلى القمر؟

وبعض هذه الأشياء لا يشبه غيرها..

لنفترض إذن أنني لا أتحلل الصفات.يبدو أن البديل هو تحديد مجموعة من الامتيازات لكل مورد.ومع ذلك، عند هذه النقطة، يتم فقدان تجانس REST.من أجل تحديد قواعد الوصول إلى أحد الموارد، يجب أن يكون لدى النظام معرفة محددة بقدرات هذا المورد.علاوة على ذلك، أصبح من المستحيل الآن نشر الأذونات بشكل عام إلى الموارد التابعة - حتى إذا كان المورد الفرعي يتمتع بامتياز يحمل نفس الاسم، فلا يوجد اتصال دلالي متأصل بين الامتيازات.يبدو لي أن تحديد مجموعة من الامتيازات القياسية المشابهة لـ REST هو الأسوأ في كلا العالمين، لذا فأنا عالق في تسلسل هرمي منفصل للأذونات لكل نوع من الموارد.

حسنًا، لقد قمنا بعمل الأنف.والقبعة.لكنه مورد!

أحد الاقتراحات التي رأيتها والتي تخفف من بعض عيوب الطريقة المذكورة أعلاه هو تحديد الأذونات كإنشاء/حذف في موارد والقراءة/الكتابة صفات.يعد هذا النظام بمثابة حل وسط بين السمات كموارد والامتيازات لكل مورد:لا يزال هناك واحد مع CRUD فقط، ولكن لأغراض الترخيص، تتعلق القراءة والتحديث بالسمات، والتي يمكن اعتبارها موارد زائفة.وهذا يوفر العديد من الفوائد العملية لمنهج السمات كموارد، على الرغم من أن السلامة المفاهيمية معرضة للخطر إلى حد ما.لا يزال من الممكن أن تنتشر الأذونات من مورد إلى مورد ومن مورد إلى مورد زائف، ولكن ليس من مورد زائف أبدًا.لم أستكشف بشكل كامل تداعيات هذه الاستراتيجية، ولكن يبدو أنها قد تكون واعدة.يخطر لي أن مثل هذا النظام من شأنه أن يعمل بشكل أفضل كجزء لا يتجزأ من النموذج.في Rails، على سبيل المثال، يمكن أن يكون تحديثًا لـ ActiveRecord.يبدو هذا جذريًا إلى حد ما بالنسبة لي، لكن الترخيص يمثل مصدر قلق أساسيًا شاملاً وقد يكون له ما يبرره.

أوه، ولا تنسى المهر

كل هذا يتجاهل مسألة الأذونات الإسنادية.من الواضح أن المستخدم يجب أن يكون قادرًا على تحرير منشوراته الخاصة، وليس منشورات أي شخص آخر.ومن الواضح أيضًا أن جدول الأذونات التي يكتبها المسؤول لا ينبغي أن يحتوي على سجلات منفصلة لكل مستخدم.وهذا ليس مطلبًا غير شائع، فالخدعة تكمن في جعله عامًا.أعتقد أنه يمكن الحصول على جميع الوظائف التي أحتاجها من خلال إنشاء قواعد مسند، بحيث يمكن تحديد مدى تطبيق القاعدة بسرعة وعلى الفور.قاعدة "allow User write Post where Author(User, Post)"سوف تترجم إلى"for all User, Post such that Author(User, Post), allow User write Post"، و "deny all write Post where Locked(Post)" ل "for all Post such that Locked(Post), deny all write Post".(سيكون من كبير إذا كان من الممكن التعبير عن كل هذه المسندات من حيث مستخدم واحد ومورد واحد.) فإن القواعد "النهائية" الناتجة من الناحية المفاهيمية ستكون غير مسندية.وهذا يثير التساؤل حول كيفية تنفيذ مثل هذا النظام.يجب أن تكون المسندات أعضاء في فئات النموذج، لكنني لست متأكدا من كيفية الرجوع إليها بأمان في سياق القواعد.إن القيام بذلك بأمان يتطلب نوعًا من التفكير.هنا مرة أخرى لدي شعور بأن هذا سيتطلب تعديلًا تحديثيًا لتنفيذ النموذج.

كيف تتهجى ذلك مرة أخرى؟

والسؤال الأخير هو كيفية تمثيل قواعد التفويض هذه على أفضل وجه كبيانات.قد يقوم جدول قاعدة البيانات بالمهمة، مع أعمدة التعداد للسماح/الرفض وC/R/U/D (أو ربما بتات CRUD؟أو ربما {C, R, U, D} × {السماح، الرفض، الوراثة}؟)، وعمود مورد بمسار.ربما، على سبيل الراحة، بت "وراثة".أنا في حيرة فيما يتعلق بالمسندات.طاولة منفصلة؟بالتأكيد الكثير من التخزين المؤقت لمنعه من الوجود أيضاً بطيء بشكل غير لائق.


أعتقد أن هذا كثير لنطلبه.لقد حاولت أداء واجباتي قبل طرح السؤال، لكن في هذه المرحلة أحتاج حقًا إلى منظور خارجي.سأكون ممتنًا لأي مساهمة قد تكون لدى أي منكم بشأن هذه المشكلة.

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

المحلول

آسف، ليس لدي الوقت الكافي لتوضيح هذا السؤال، ولكن من الجيد رؤية بعض الأسئلة المدروسة جيدًا حول SO.وهنا بعض التعليقات:

لا تقع في فخ تعيين أفعال HTTP إلى CRUD.نعم، احصل على خريطة وحذفها بشكل نظيف جدًا، ولكن PUT يمكنه القيام بالإنشاء والتحديث (ولكن الاستبدال الكامل فقط) وPOST هو فعل بدل.

يعد استخدام السمات لتمثيل حالة الكائن مجرد أسلوب واحد لإدارة الحالة.أعتقد أنه يمكنك تخيل ما قد يفعله الطلب التالي:

POST /LockedPosts?url=/Post/2010

يعد المورد الفرعي أيضًا أسلوبًا صالحًا لإدارة الحالة الحالية للمورد.لن أشعر بأنني مضطر للتعامل مع سمات "حالة" المورد وسمات "بياناته" بطريقة متسقة.

ستؤدي محاولة تعيين الموارد مباشرة إلى الجداول إلى تقييدك بشكل خطير.لا تنس أنه عندما تتبع قيود REST، تصبح فجأة محدودًا جدًا في الأفعال المتوفرة لديك.يجب أن تكون قادرًا على تعويض ذلك من خلال الإبداع في الموارد التي تستخدمها.سيؤدي تقييد نفسك بمورد واحد يساوي جدولًا واحدًا إلى الحد بشدة من وظائف التطبيق النهائي الخاص بك.

نرى بانتظام مستخدمي Rails وASP.NET MVC وWCF Rest ينشرون أسئلة هنا على StackOverflow حول كيفية القيام بأشياء معينة ضمن قيود REST.لا تكمن المشكلة غالبًا في قيود REST ولكن في قيود إطار العمل في دعمه لتطبيقات RESTful.أعتقد أنه من الضروري أولاً العثور على حل RESTful لمشكلة ما ثم معرفة ما إذا كان من الممكن إعادة تعيين ذلك إلى إطار العمل الذي تختاره.

بقدر ما يتعلق الأمر بإنشاء نموذج أذونات موجود بحبوب أدق من المورد نفسه.تذكر أن إحدى قيود REST الرئيسية هي الوسائط التشعبية.يمكن استخدام الوسائط التشعبية لأكثر من مجرد البحث عن الكيانات ذات الصلة، ويمكن استخدامها أيضًا لتمثيل انتقالات الحالة الصالحة/المسموح بها.إذا قمت بإرجاع تمثيل يحتوي على روابط مضمنة، بناءً على الأذونات بشكل مشروط، فيمكنك التحكم في الإجراءات التي يمكن تنفيذها بواسطة من.أي.إذا كان لدى المستخدم أذونات لفتح POST 342، فيمكنك إرجاع الرابط التالي المضمن في التمثيل:

<Link href="/UnlockedPosts?url=/Post/342" method="POST"/>

إذا لم يكن لديهم هذا الإذن، فلا تعيد الرابط.

أعتقد أن إحدى الصعوبات التي تواجهك هنا هي أنك تحاول تناول مشكلة كبيرة جدًا في وقت واحد.أعتقد أنك بحاجة إلى إلقاء نظرة على واجهة RESTful التي تحاول كشفها للعميل باعتبارها مشكلة مختلفة عن الطريقة التي ستدير بها الأذونات والمسندات من أجل إدارة الترخيص في نموذج المجال الخاص بك.

أدرك أنني لم أجب بشكل مباشر على أي من أسئلتك، ولكن آمل أن أكون قد قدمت بعض وجهات النظر التي قد تساعد بطريقة ما.

نصائح أخرى

لقد اكتشفت مؤخرًا حلاً للمصادقة يبدو أنه يعالج معظم مخاوفي.إذا كنت تفضل هذا السؤال، فقد يكون محل اهتمامك:

https://github.com/stffn/declarative_authorization

كما أشار داريل - REST ليس فظًا.إذا وجدت أن مواردك المحددة غير دقيقة للغاية بحيث لا توفر الواجهة الموحدة تحكمًا كافيًا، فقم بتقسيم المورد الخاص بك إلى موارد فرعية واستخدم المورد الأصلي باعتباره "مجموعة" من الارتباطات التشعبية لمكوناته.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top