it-swarm.asia

كيفية جعل POST JSON بسيطة باستخدام Django REST Framework؟ CSRF الرمز المميز مفقود أو غير صحيح

سأكون ممتنًا لشخص ما يوضح لي كيفية تقديم طلب POST بسيط باستخدام JSON مع Django REST إطار عمل. لا أرى أي أمثلة على ذلك في البرنامج التعليمي في أي مكان؟

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

{
    "name": "Manager", 
    "description": "someone who manages"
}

إليكم طلب حليقة في محطة باش موجه:

curl -X POST -H "Content-Type: application/json" -d '[
{
    "name": "Manager", 
    "description": "someone who manages"
}]'


http://localhost:8000/lakesShoreProperties/role

عنوان URL

http://localhost:8000/lakesShoreProperties/roles

يعمل مع طلب GET ، ويمكنني سحب جميع الأدوار في قاعدة البيانات ، لكن لا يمكنني إنشاء أي أدوار جديدة. ليس لدي أي أذونات مجموعة. أنا أستخدم طريقة عرض قياسية في views.py

class RoleDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Role.objects.all()
    serializer_class = RoleSerializer
    format = None

class RoleList(generics.ListCreateAPIView): 
        queryset = Role.objects.all()
        serializer_class = RoleSerializer
        format = None

وفي بلدي urls.py لهذا التطبيق ، تكون تعيينات عرض عنوان url ذات الصلة صحيحة:

url(r'^roles/$', views.RoleList.as_view()),
url(r'^role/(?P<pk>[0-9]+)/$', views.RoleDetail.as_view()),

رسالة الخطأ هي:

{
    "detail": "CSRF Failed: CSRF token missing or incorrect."
}

ما يجري هنا وما هو الإصلاح لهذا؟ هل المضيف المحلي طلب عبر الموقع؟ لقد أضفت @csrf_exempt إلى RoleDetail و RoleList لكن لا يبدو أنه يغير أي شيء. هل يمكن إضافة هذا الديكور إلى فصل دراسي ، أم أنه يجب إضافته إلى طريقة ما؟ عند إضافة تزيين @csrf_exempt ، يصبح خطأي:

Request Method: POST
Request URL:    http://127.0.0.1:8000/lakeshoreProperties/roles/
Django Version: 1.5.1
Exception Type: AttributeError
Exception Value:    
'function' object has no attribute 'as_view'

بعد ذلك ، قمت بتعطيل CSRF خلال التطبيق بأكمله ، والآن أتلقى هذه الرسالة:

{"non_field_errors": ["بيانات غير صالحة"]} عندما يكون كائن JSON الذي أعرفه صالحًا json. إنه خطأ غير ميداني ، لكنني عالق هنا.

حسنًا ، اتضح أن ملف json الخاص بي لم يكن صالحًا؟

{
    "name": "admin", 
    "description": "someone who administrates"
}

ضد

[
    {
        "name": "admin",
        "description": "someone who administrates"
    }
]

امتلاك الأقواس المغلقة [] ، يؤدي إلى فشل طلب POST. ولكن باستخدام أداة التحقق من jsonlint.com ، يتم التحقق من صحة كل من كائنات json الخاصة بي.

التحديث : كانت المشكلة مع إرسال POST مع PostMan ، وليس في الواجهة الخلفية. راجع https://stackoverflow.com/a/17508420/203312

44
user798719

ربما تحتاج إلى إرسال الرمز المميز CSRF مع طلبك. راجع https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax

تحديث: لأنك جربت بالفعل إعفاء CSRF ، فقد يساعد ذلك (بناءً على إصدار Django الذي تستخدمه): https://stackoverflow.com/a/14379073/977931

10
stellarchariot

يتم استثناء CSRF افتراضيًا في Django REST Framework. لذلك ، حليقة POST طلب يعمل بشكل جيد. إرجاع استدعاء طلب POSTMAN CSRF غير صحيح لأن POSTMAN تضمن رمز csrf إذا كان موجودًا في ملفات تعريف الارتباط. يمكنك حل هذا عن طريق تنظيف ملفات تعريف الارتباط.

34
Terry Lam

إنه من REST إعدادات Framework. في ملف settings.py ، يجب أن يكون لديك REST_FRAMEWORK ما يلي.

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

سيؤدي هذا إلى تعيين REST Framework الخاص بك لاستخدام مصادقة الرمز المميز بدلاً من مصادقة csrf. ومن خلال تعيين الإذن لـ AllowAny ، يمكنك المصادقة فقط على المكان الذي تريده.

24
pharingee

حسناً ، الآن بالطبع أستعيد ما قلته. CSRF لا يعمل على النحو المنشود.

كنت أقوم بطلب POST باستخدام مكون chrome يسمى POSTMAN. فشل طلب POST مع تمكين CSRF.

لكن حليقة POST طلب استخدام

curl -X POST -H "Content-Type: application/json" -d '
{
    "name": "Manager",
    "description": "someone who manages"
}' http://127.0.0.1:8000/lakeshoreProperties/roles/

يعمل بشكل جيد ... اضطررت إلى خلع المشابك ، أي ، [] ، والتأكد من وجود شرطة مائلة بعد "الأدوار" ، أي أن الأدوار/، ولم يؤدي csrf الممكّن إلى حدوث أية أخطاء.

لست متأكدًا من أن الفرق بين الاتصال باستخدام POSTMAN هو مقابل استخدام curl ، ولكن POSTMAN يتم تشغيله في متصفح الويب وهو الفرق الأكبر. ومع ذلك ، قمت بتعطيل csrf لقائمة RoleList بأكملها ، لكن طلبًا واحدًا متطابقًا يعمل مع Curl ، لكنه فشل مع POSTMAN.

10
user798719

لتقديم تحديث عن الحالة الحالية ، ولخص بعض الإجابات:

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

عادة ما تحتاج طلبات أجاكس التي يتم إجراؤها على موقع مختلف عن واجهة برمجة التطبيقات التي تتواصل معها إلى استخدام نظام مصادقة غير قائم على الجلسة ، مثل TokenAuthentication.

لذلك ، قد تعمل الحلول التي توصي باستبدال SessionAuthentication بـ TokenAuthentication على حل المشكلة ، ولكنها ليست بالضرورة صحيحة تمامًا.

للحماية من هذا النوع من الهجمات ، عليك القيام بأمرين:

  1. تأكد من أن عمليات HTTP "الآمنة" ، مثل GET ، HEAD و OPTIONS لا يمكن استخدامها لتغيير أي حالة من جانب الخادم.

  2. تأكد من أن أي عمليات HTTP "غير آمنة" ، مثل POST ، PUT ، PATCH و DELETE ، تتطلب دائمًا رمز مميز CSRF صالحًا. إذا كنت تستخدم SessionAuthentication ستحتاج إلى تضمين رموز CSRF صالحة لأي _ POST أو PUT أو PATCH أو DELETE عمليات .

من أجل تقديم AJAX ، تحتاج إلى تضمين رمز CSRF في رأس HTTP ، كما هو موضح في = Django documentation.

لذلك ، من المهم أن يتم تضمين csrf في الرأس ، على سبيل المثال هذه الإجابة يقترح.

المرجع: العمل مع أجاكس ، CSRF و CORS ، Django REST وثائق إطار العمل .

4
Wtower

كما قلت عنوان URL الخاص بك كان

http://localhost:8000/lakesShoreProperties/roles

ساعي البريد لديه بعض القضايا مع المضيف المحلي. إرسال POST إلى 127.0.0.1:8000/your-api/endpoint بدلا من ذلك خدعة بالنسبة لي.

3
Thosse

القديم ساعي البريد يواجه مشكلة مع الرموز csrf لأنه لا يعمل مع ملفات تعريف الارتباط.

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

1
Musharraf Al-tamimi

إذا قمت بتعيين AllowAny إذن وتواجه مشكلة csrf

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny'
    ]
}

ثم وضع التالي في settings.py سوف يحل المشكلة

REST_SESSION_LOGIN = False
0
navyad