Django-rest-framework: يجب أن يأذن DRF بجميع طلبات OPTIONS بشكل افتراضي

تم إنشاؤها على ٢١ نوفمبر ٢٠١٧  ·  22تعليقات  ·  مصدر: encode/django-rest-framework

بعد المناقشة على # 908

تمت معالجة أذونات طلبات OPTIONS (بيانات التعريف) بشكل غير صحيح في DRF.

وفقًا لمواصفات W3C ، لم تتم مصادقة جميع طلبات الاختبار المبدئي OPTIONS ، مما يعني أن المستخدمين سيحصلون دائمًا على خطأ 401 عند الاختبار المسبق لطلب نقاط النهاية المصادق عليها ، لأن المتصفحات الحديثة لا ترسل هذا أبدًا وفقًا للمواصفات:

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

  • قم بتضمين رأس Access-Control-Request-Method مع قيمة حقل رأس طريقة الطلب (حتى عندما تكون هذه طريقة بسيطة).
  • إذا لم تكن رؤوس طلب المؤلف فارغة ، فقم بتضمين رأس Access-Control-Request-Headers مع قائمة مفصولة بفواصل لأسماء حقل الرأس من رؤوس طلبات المؤلف بترتيب معجمي ، كل منها محوّل إلى أحرف صغيرة ASCII (حتى عندما يكون واحدًا أو أكثر هي رأس بسيط).
  • استبعاد رؤوس طلب المؤلف.
  • ➡️ استبعاد بيانات اعتماد المستخدم .
  • استبعاد هيئة الكيان الطلب.

أعتقد أن هذا يجب أن يكون السلوك الافتراضي هنا.
يجب أن يفوض DRF جميع طلبات OPTIONS افتراضيًا لفئات الأذونات القياسية (IsAuthenticated ، IsAdminUser ، إلخ) وقد يتجاوز المستخدمون ذلك عندما يحتاجون صراحة إلى حماية معلومات البيانات الوصفية (انتهاك توافق CORS القياسي)

خطوات التكاثر:

views.py

class MyView(APIView):

    permission_classes = (IsAuthenticated,)

urls.py

urlpatterns = [
    url(r'^myview/', MyView.as_view()),
]

وحدة التحكم

http GET http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

http OPTIONS http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

سلوك متوقع

http GET http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

http OPTIONS http://127.0.0.1:8000/myview/
HTTP/1.0 200 OK

عمل مؤقت

class IsAuthenticated(permissions.IsAuthenticated):

    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return super(IsAuthenticated, self).has_permission(request, view)

التعليق الأكثر فائدة

إصدار DRF: 3.7.3.1
بايثون 3.6.3

لم يعمل الحل المؤقت المذكور أعلاه بالنسبة لي. تمت مصادقة جميع الطلبات بغض النظر عما إذا كانت PUT ، أو POST ، أو GET ، أو OPTIONS ، وما إلى ذلك.

عملت على تغييرها إلى:

# myapp/permissions.py
from rest_framework.permissions import IsAuthenticated

class AllowOptionsAuthentication(IsAuthenticated):
    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return request.user and request.user.is_authenticated

وفي settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication',),
    'DEFAULT_PERMISSION_CLASSES': (
        'myapp.permissions.AllowOptionsAuthentication',
    )
}

ال 22 كومينتر

إصدار DRF: 3.7.3.1
بايثون 3.6.3

لم يعمل الحل المؤقت المذكور أعلاه بالنسبة لي. تمت مصادقة جميع الطلبات بغض النظر عما إذا كانت PUT ، أو POST ، أو GET ، أو OPTIONS ، وما إلى ذلك.

عملت على تغييرها إلى:

# myapp/permissions.py
from rest_framework.permissions import IsAuthenticated

class AllowOptionsAuthentication(IsAuthenticated):
    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return request.user and request.user.is_authenticated

وفي settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication',),
    'DEFAULT_PERMISSION_CLASSES': (
        'myapp.permissions.AllowOptionsAuthentication',
    )
}

لقد واجهت نفس المشكلة أيضًا. أوافق على الحل المقترح وشكرًا على الحل المؤقت!

ليس 100٪ على قناعة بأن "يجب أن يأذن كل OPTIONS طلبات افتراضيا" هو بالضبط السلوك نريد لأن هناك الكثير من المطورين باستخدام إطار REST الذين يستخدمون OPTIONS طلبات حالات أخرى من CORS طلبات قبل الطيران.

ومع ذلك ، أعتقد أننا ربما نريد أن يكون لدينا خيار CORS مبارك . لا أعرف ما إذا كان هذا يعني أنه يجب علينا تضمين https://github.com/ottoyiu/django-cors-headers/ مباشرةً ، أو إذا كان ينبغي لنا الرجوع إليه بدرجة أكبر.

هل يتم حل هذه المشكلة بمجرد استخدام تلك الحزمة؟

هذه الحزمة ليست حقًا soluton ، فهي تلحق فقط رؤوس CORS ولكنها لا تصلح حقيقة أن OPTIONS ترجع HTTP401 إذا لم يتم منح إذن DRF بشكل خاص لجميع الطلبات غير المصادق عليها.

يجب تقديم IMO بالعكس ، أي مسموح به بشكل افتراضي مع إشعار تغيير التغيير.
هذا هو السلوك المتوقع وفقًا لمواصفات W3C ، كما أن ذكر طرف ثالث في المستند لتصحيح تطبيق خاطئ ليس حلاً نظيفًا حقًا ...

لذلك على الرغم من وجود أشخاص يستخدمون OPTIONS لأشياء لا تتعلق بـ CORS (أنا واحد منهم) ، فمن المحتمل أن يكون هناك الكثير من الأشياء التي تتوقع ضمنيًا أن تعمل خارج الصندوق ، نظرًا لأن آليات CORS يتم فرضها بواسطة المزيد والمزيد من المتصفحات. في الواقع ، من المحتمل أن تولد هذه الآليات 99٪ + من طلبات OPTIONS عبر الويب.

صراع مثير للاهتمام. أفهم تمامًا مشكلة وجود سماح ضمني افتراضيًا في طريقة OPTIONS. أنا بطبيعة الحال أكثر انحيازًا نحو حل أكثر أمانًا وأفترض أن ذلك يعتمد على غرض المطور من DRF. لذا يبدو الرفض الافتراضي أكثر ملاءمة لي.

من الممكن أيضًا أن تنطبق مواصفات W3C للسماح بالخيارات فقط في سياق CORS. من الواضح أن DRF ليس لديه طريقة لمعرفة السياق ويجب أن يكون إعدادًا مقدمًا للمطور.

إذا كانت CORS مقصودة ، فقم بالسماح بكل طلبات OPTIONS. CORS غير مقصودة بشكل افتراضي.

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

+1

tomchristie هل لديك أي فكرة عن موعد تحديث / إصلاح إصدار رئيسي؟ أنا أيضًا أعالج هذه المشكلة.

حلmedakk مثالي ، في غضون ذلك!

Milestoning هذا للتأكد من أنه يحصل على الاعتبار المناسب لـ 3.9

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

def check_permissions(self, request):
        if request.method == 'OPTIONS':
            return
        super(MyApiView, self).check_permissions(request)

بالعودة إلى هذا بعد النظر فيه أكثر - تتعامل حزمة https://github.com/OttoYiu/django-cors-headers مسبقًا مع طلبات OPTIONS في البرامج الوسيطة ، وترجع ردًا مباشرة. لا يهم ما يفعله إطار عمل REST هنا لأنه تم اعتراض الطلب / الاستجابة قبل أن يصل إلى إطار عمل REST على الإطلاق.

ليس واضحًا بالنسبة لي أن لدينا مشكلة هنا.

لا تلمس استجابات الاختبار المبدئي إطار عمل REST: https://github.com/ottoyiu/django-cors-headers/blob/master/corsheaders/middleware.py#L83

شكرا. نحن لا نستخدم رؤوس django-cors ، لكن ربما يجب أن نستخدمها.
ما زلت أتفق مع التعليقات السابقة بأن DRF لا ينبغي أن يحتاج إلى حزمة خارجية للتعامل مع طلبات CORS المتوافقة مع W3C.

نعم ، هناك مجموعة طرق / حزم خارجية للتحايل على المشكلة.
ولكن مرة أخرى ، تم إنشاء هذه البطاقة لأن DRF غير متوافق مع مواصفات W3C CORS ، ويجب إصلاحها.

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

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

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

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

دعونا نخفض المستوى.

الوسيطة هي المكان المناسب للتعامل مع رؤوس CORS. يمكننا أن نبني ذلك في إطار REST، ولكن حزمة موجودة بالفعل أنها تغطي طيف حقا.

الجسم الذي يحدث لإطار عمل REST لإرجاعه لطلبات OPTIONS غير ذي صلة هنا ، حيث يجب اعتراض طلبات CORS المحددة مسبقًا بواسطة البرامج الوسيطة على أي حال ، ويمكن أن تكون طلبات CORS القياسية بأي طريقة HTTP.

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

يبدو لي أن حل البرامج الوسيطة وحده غير كاف أو على الأقل يتطلب بعض التعاون من DRF. إذا نظرت إلى الكود المُشار إليه ، يمكنك أن ترى أن الافتراضيات العامة تُستخدم لتزويد رؤوس CORS. ولكن كيف يمكنني معرفة الرؤوس التي يدعمها كل عرض على مستوى العالم؟

على هذا النحو ، أود أن أرى طريقة قياسية للبرمجيات الوسيطة للربط بخيارات التكوين هذه من مجموعات العرض / العروض: طريقة allowed_cors_headers على سبيل المثال.

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

قد يكون من المفيد أيضًا أن يكون لديك تجاوز على مستوى جهاز التوجيه لتطبيقه على جميع طرق العرض في جهاز التوجيه.

اعتبارات إضافية:

  • متفاوتة على أساس الأصل
  • متفاوتة على أساس نوع المحتوى

هذا ليس خياري المفضل ولكن الاتجاه يتجه نحو استخدام طرف ثالث.

أعتقد أنه يمكننا إغلاق هذه البطاقة بمجرد تحديث الوثائق بالمعلومات المناسبة لمستخدمي CORS (مثل: "احذر ، لا يفي DRF بمواصفات W3C CORS في طلبات OPTIONS. إذا كنت تستخدم OPTIONS لـ CORS ، فلا تنس إضافة البرامج الوسيطة المناسبة وإلا فقد تفشل طلبات الاختبار المبدئي الخاصة بك بسبب نقص التفويض "وما إلى ذلك)

الوثائق الحالية https://www.django-rest-framework.org/topics/ajax-csrf-cors/#cors معقولة تمامًا ، والتعامل مع CORS في البرامج الوسيطة هو النهج الصحيح في أي حال.

ولكن كيف يمكنني معرفة الرؤوس التي يدعمها كل عرض على مستوى العالم؟

لست بحاجة إلى ذلك - فأنت بحاجة إلى معرفة سياسة CORS الخاصة بالموقع.

يسعدني قبول طلب سحب مما يجعل مستندات CORS أكثر بروزًا أو تضمينها في مكان آخر مناسب أيضًا. بخلاف ذلك ، لا توجد مشكلة قابلة للتنفيذ هنا.

سوء فهمي للمواصفات ، عفوًا.

في هذه الحالة ، سيتم تضمين الدعم بشكل أفضل في مساهمة مواقع django
الحزمة ، وليس drf.

لو مار. 19 فيفر. 2019 10:22 صباحًا ، Tom Christie [email protected] أ
écrit:

الوثائق الموجودة
https://www.django-rest-framework.org/topics/ajax-csrf-cors/#cors هو
معقول تمامًا ، والتعامل مع CORS في البرمجيات الوسيطة هو الصحيح
نهج في أي حال.

ولكن كيف يمكنني معرفة الرؤوس التي يدعمها كل عرض على مستوى العالم؟

لست بحاجة إلى ذلك - فأنت بحاجة إلى معرفة سياسة CORS الخاصة بالموقع.

-
أنت تتلقى هذا لأنك علقت.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/encode/django-rest-framework/issues/5616#issuecomment-465146969 ،
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/AFhtlM6bG-Bs2CvoO972pIfwvxLHbzAxks5vPAjAgaJpZM4Qlvkn
.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات