Django Rest Framework rimuove csrf

So che ci sono risposte riguardo a Django Rest Framework, ma non sono riuscito a trovare una soluzione al mio problema.

Ho un’applicazione che ha l’autenticazione e alcune funzionalità. Ho aggiunto una nuova app, che utilizza Django Rest Framework. Voglio usare la libreria solo in questa app. Voglio anche fare la richiesta POST, e ricevo sempre questa risposta:

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

Ho il codice seguente:

 # urls.py from django.conf.urls import patterns, url urlpatterns = patterns( 'api.views', url(r'^object/$', views.Object.as_view()), ) # views.py from rest_framework.views import APIView from rest_framework.response import Response from django.views.decorators.csrf import csrf_exempt class Object(APIView): @csrf_exempt def post(self, request, format=None): return Response({'received data': request.data}) 

Voglio aggiungere l’API senza influenzare l’applicazione corrente. Quindi le mie domande sono: come posso disabilitare CSRF solo per questa app?

Perché questo errore sta accadendo?

Ciò sta accadendo a causa dello schema SessionAuthentication predefinito utilizzato da DRF. SessionAuthentication di DRF utilizza il framework di sessione di Django per l’autenticazione che richiede il controllo di CSRF.

Quando non definisci alcuna authentication_classs nella tua vista / viewet, DRF utilizza questa class di autenticazione come predefinita.

 'DEFAULT_AUTHENTICATION_CLASSES'= ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication' ), 

Dal momento che il DRF deve supportare sia l’autenticazione di sessione che quella non di sessione alle stesse viste, applica il controllo CSRF solo agli utenti autenticati. Ciò significa che solo le richieste autenticate richiedono token CSRF e le richieste anonime possono essere inviate senza token CSRF.

Se stai utilizzando un’API in stile AJAX con SessionAuthentication, devi includere un token CSRF valido per qualsiasi chiamata al metodo HTTP “non sicura”, come le richieste PUT, PATCH, POST or DELETE .

Cosa fare allora?

Ora per disabilitare il controllo csrf, è ansible creare una class di autenticazione personalizzata CsrfExemptSessionAuthentication che si estenda dalla class SessionAuthentication predefinita. In questa class di autenticazione, sostituiremo il controllo enforce_csrf() che stava accadendo all’interno della SessionAuthentication effettiva.

 from rest_framework.authentication import SessionAuthentication, BasicAuthentication class CsrfExemptSessionAuthentication(SessionAuthentication): def enforce_csrf(self, request): return # To not perform the csrf check previously happening 

Dal tuo punto di vista, puoi definire le authentication_classs come:

 authentication_classs = (CsrfExemptSessionAuthentication, BasicAuthentication) 

Questo dovrebbe gestire l’errore csrf.

Soluzione più semplice:

In views.py, utilizza le parentesi graffe CsrfExemptMixin e authentication_class:

 # views.py from rest_framework.views import APIView from rest_framework.response import Response from django.views.decorators.csrf import csrf_exempt from braces.views import CsrfExemptMixin class Object(CsrfExemptMixin, APIView): authentication_classs = [] def post(self, request, format=None): return Response({'received data': request.data}) 

Se non si desidera utilizzare l’autenticazione basata sulla sessione, è ansible rimuovere l’ Session Authentication da REST_AUTHENTICATION_CLASSES e questo rimuoverà automaticamente tutti i problemi basati su csrf. Ma in quel caso le apis navigabili potrebbero non funzionare.

Oltre a questo errore non dovrebbe venire anche con l’autenticazione di sessione. È necessario utilizzare l’autenticazione personalizzata come TokenAuthentication per i propri apis e assicurarsi di inviare Accept:application/json e Content-Type:application/json (a condizione che si stia utilizzando json) nelle richieste insieme al token di autenticazione.

Per tutti quelli che non hanno trovato una risposta utile. Sì DRF rimuove automaticamente la protezione CSRF se non si utilizza la CLASSE DI AUTENTICAZIONE SessionAuthentication , ad esempio, molti sviluppatori utilizzano solo JWT:

 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', ), 

Ma il problema con CSRF not set può essere verificato da qualche altra ragione, per esempio non hai aggiunto correttamente il percorso alla tua vista:

 url(r'^api/signup/', CreateUserView), # <= error! DRF cant remove CSRF because it is not as_view that does it! 

invece di

 url(r'^api/signup/', CreateUserView.as_view()), 

Sono colpito dallo stesso problema. Ho seguito questo riferimento e ha funzionato. La soluzione è creare un middleware

Aggiungi il file disable.py in una delle tue app (nel mio caso è ‘myapp’)

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

E aggiungi il middileware a MIDDLEWARE_CLASSES

 MIDDLEWARE_CLASSES = ( myapp.disable.DisableCSRF, ) 

Modifica urls.py

Se gestisci i percorsi in urls.py, puoi avvolgere i percorsi desiderati con csrf_exempt () per escluderli dal middleware di verifica CSRF.

 from django.conf.urls import patterns, url from django.views.decorators.csrf import csrf_exempt import views urlpatterns = patterns('', url(r'^object/$', csrf_exempt(views.ObjectView.as_view())), ... ) 

In alternativa, come decoratore, alcuni potrebbero trovare l’uso del decoratore @csrf_exempt più adatto alle loro esigenze

per esempio,

 from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse @csrf_exempt def my_view(request): return HttpResponse('Hello world') 

dovrebbe avere il lavoro fatto!

Se si sta utilizzando un ambiente virtuale esclusivo per la propria applicazione, è ansible utilizzare il seguente approccio senza utilizzare altre applicazioni.

Ciò che hai osservato accade perché rest_framework/authentication.py ha questo codice nel metodo di authenticate della class SessionAuthentication :

 self.enforce_csrf(request) 

È ansible modificare la class Request per avere una proprietà denominata csrf_exempt e inizializzarla all’interno della rispettiva class View su True se non si desiderano i controlli CSRF. Per esempio:

Quindi, modifica il codice sopra riportato come segue:

 if not request.csrf_exempt: self.enforce_csrf(request) 

Ci sono alcune modifiche correlate che dovresti fare nella class Request . Un’implementazione completa è disponibile qui (con descrizione completa): https://github.com/piaxis/django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed

La mia soluzione è mostrata colpo. Basta decorare la mia class.

 from django.views.decorators.csrf import csrf_exempt @method_decorator(csrf_exempt, name='dispatch') @method_decorator(basic_auth_required( target_test=lambda request: not request.user.is_authenticated ), name='dispatch') class GenPedigreeView(View): pass