2013-07-06 18 views
42

Apprezzerei qualcuno che mi mostri come fare una semplice richiesta POST usando JSON con il framework Django REST. Non vedo alcun esempio di questo nel tutorial, da nessuna parte?Come creare un JSON POST semplice con Django REST Framework? Token CSRF mancante o errato

Ecco il mio oggetto modello Role che mi piacerebbe pubblicare. Questo sarà un Ruolo nuovo di zecca che vorrei aggiungere al database, ma sto ricevendo un errore 500.

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

Ecco la mia richiesta ricciolo in un terminale bash:

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


http://localhost:8000/lakesShoreProperties/role 

L'URL

http://localhost:8000/lakesShoreProperties/roles 

funziona con una richiesta GET, e posso tirare giù tutti i ruoli in il database, ma non riesco a creare nuovi ruoli. Non ho impostato le autorizzazioni. Sto usando una vista standard in 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 

E nei miei urls.py per questa applicazione, l'url relativo - vista mappature sono corrette:

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

messaggio di errore è:

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

Cosa sta succedendo qui e quale è la correzione per questo? Localhost è una richiesta cross-site? Ho aggiunto @csrf_exempt a RoleDetail e RoleList ma non sembra cambiare nulla. Questo decoratore può essere aggiunto a una classe o deve essere aggiunto a un metodo? Aggiungendo il @csrf_exempt decorare, il mio errore diventa:

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' 

Poi ho disabilitato CSRF throughtout l'intera applicazione, e io ora ottenere questo messaggio:

{ "non_field_errors": [ "i dati non valido"]} quando il mio oggetto JSON che conosco è json valido. È un errore non di campo, ma sono bloccato qui.

Bene, si scopre che il mio json non era valido?

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

vs

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

Avere le staffe di cinta [], provoca la richiesta POST a fallire. Ma usando il validatore jsonlint.com, entrambi i miei oggetti json convalidano.

Aggiornamento: il problema era con l'invio del POST con PostMan, non nel back-end. Vedi https://stackoverflow.com/a/17508420/203312

+0

'RoleSerializer' qualcosa che hai definito? Forse vale la pena esaminarlo. – stellarchariot

risposta

9

Probabilmente è necessario inviare il token CSRF con la richiesta. Scopri https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax

Update: Perché hai già provato esentando CSRF, forse questo potrebbe aiutare (a seconda della versione di Django si sta utilizzando): https://stackoverflow.com/a/14379073/977931

+0

Grazie. Sembra che CSRF sia solo un sacco di male per i miei scopi in questo momento. Disabilitare rende la mia richiesta POST funziona bene ora. Mi piacerebbe mantenere abilitato CSRF, ma non funziona bene con Django REST Framework. – user798719

+0

Aggiornato il collegamento ai documenti Django. – Duncan

+0

Il link più recente è https://docs.djangoproject.com/en/dev/ref/csrf/#ajax – Wtower

10

OK, bene ora naturalmente prendo indietro che cosa Ho detto. CSRF funziona come previsto.

Stavo facendo una richiesta POST usando un plugin chrome chiamato POSTMAN. La mia richiesta POST fallisce con CSRF abilitato.

Ma una richiesta POST ricciolo utilizzando

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

funziona bene ... ho dovuto togliere le parentesi graffe, ad esempio, [], e assicurarsi che ci sia una barra dopo la 's' in ruoli Ad esempio, ruoli/e csrf abilitati non hanno generato alcun errore.

Non sono sicuro di quale sia la differenza tra la chiamata tramite POSTMAN rispetto all'utilizzo di curl, ma POSTMAN viene eseguito nel browser Web che è la più grande differenza. Detto questo, ho disabilitato csrf per l'intera classe RoleList ma una richiesta identica funziona con Curl, ma fallisce con POSTMAN.

33

CSRF è esonerato di default in Django REST Framework. Pertanto, la richiesta di arricciamento POST funziona correttamente. Chiamata di richiesta POSTMAN restituita CSRF errata perché POSTMAN includeva il token csrf se è stato trovato in Cookie. Puoi risolvere questo problema pulendo i cookie.

+1

Grazie per il commento del postino! Sono stati totalmente i cookies a causare questo per me :) – Gezim

3

Come ha detto l'URL è stato

http://localhost:8000/lakesShoreProperties/roles

postino ha alcuni problemi con localhost. L'invio del POST a 127.0.0.1:8000/your-api/endpoint invece ha fatto il trucco per me.

25

Viene dalle impostazioni del framework REST. nel tuo file settings.py, il tuo REST_FRAMEWORK dovrebbe avere il seguente.

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

In questo modo il framework REST utilizzerà l'autenticazione token anziché l'autenticazione csrf. E impostando l'autorizzazione su AllowAny, è possibile autenticare solo dove si desidera.

+0

Questo ha risolto anche il mio problema. Ho usato 'rest_framework.permissions.IsAuthenticated' invece di' AllowAny' e funziona perfettamente. – wcyn

1

il vecchio Postman ha un problema con i token csrf perché non funziona con i cookie.

Ti suggerisco di passare alla nuova versione di postman, funziona con i cookie e non dovrai affrontare nuovamente questo problema.

0

se è stata impostata AllowAny permesso e di fronte a voi con l'edizione csrf

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

mettendo poi in seguito nel settings.py risolverà il problema

REST_SESSION_LOGIN = False 
4

Per fornire un aggiornamento sullo stato corrente, e sum un paio di risposte:

richieste AJAX che vengono effettuate all'interno dei s contesto come l'API con cui stanno interagendo utilizzerà in genere SessionAuthentication. Ciò garantisce che, una volta che un utente ha effettuato l'accesso, tutte le richieste AJAX effettuate possono essere autenticate utilizzando la stessa autenticazione basata su sessione utilizzata per il resto del sito Web.

Le richieste AJAX effettuate su un sito diverso dall'API con cui stanno comunicando in genere devono utilizzare uno schema di autenticazione non basato sulla sessione, ad esempio TokenAuthentication.

Pertanto, le risposte che raccomandano di sostituire SessionAuthentication con TokenAuthentication può risolvere il problema, ma non sono necessariamente del tutto corretta.

Per difendersi da questo tipo di attacchi, è necessario fare due cose:

  1. Assicurarsi che il 'sicuri' HTTP operazioni, come ad esempio GET, HEAD e OPTIONS non può essere utilizzato per modificare qualsiasi stato lato server.

  2. Assicurarsi che tutte le operazioni HTTP 'non sicure', come ad esempio POST, PUT, PATCH e DELETE, richiedono sempre un token CSRF valida. Se stai usando SessionAuthentication è necessario includere valida CSRF token per eventuali operazioni POST, PUT, PATCH o DELETE.

Al fine di effettuare richieste AJAX, è necessario includere CSRF token nell'intestazione HTTP, come descritto nella documentazione di Django.

Pertanto, è importante che csrf è incluso nell'intestazione, come ad esempio this answer suggerisce.

Riferimento: Working with AJAX, CSRF & CORS, Django REST framework documentation.

3

È possibile anche disattivare il CSRF per rendere il proprio middleware:

class DisableCSRF(object): 
    def process_request(self, request): 
     setattr(request, '_dont_enforce_csrf_checks', True) 

per inserire questa middleware nel file settings.py in MIDDLEWARE_CLASSES.

Problemi correlati