Je sais qu'il existe des réponses concernant Django Rest Framework, mais je n'ai pas trouvé de solution à mon problème.
J'ai une application qui a une authentification et des fonctionnalités. J'ai ajouté une nouvelle application, qui utilise Django Rest Framework. Je veux utiliser la bibliothèque uniquement dans cette application. De plus, je souhaite faire la demande POST, et je reçois toujours cette réponse:
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
J'ai le code suivant:
# 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})
Je veux ajouter l'API sans affecter l'application actuelle. Mes questions sont donc: comment puis-je désactiver CSRF uniquement pour cette application?
Pourquoi cette erreur se produit-elle?
Cela se produit à cause du schéma par défaut SessionAuthentication
utilisé par DRF. DRF SessionAuthentication
utilise le cadre de session de Django pour l'authentification, ce qui nécessite la vérification de CSRF.
Lorsque vous ne définissez aucun authentication_classes
dans votre vue/jeu de vues, DRF utilise ces classes d'authentification par défaut.
'DEFAULT_AUTHENTICATION_CLASSES'= (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
),
Étant donné que DRF doit prendre en charge l’authentification basée sur la session et l’authentification sans session sur les mêmes vues, il impose le contrôle CSRF aux utilisateurs authentifiés uniquement. Cela signifie que seules les demandes authentifiées nécessitent des jetons CSRF et que des demandes anonymes peuvent être envoyées sans jetons CSRF.
Si vous utilisez une API de style AJAX avec SessionAuthentication, vous devez inclure un jeton CSRF valide pour tout appel de méthode HTTP "non sécurisé", tel que les demandes PUT, PATCH, POST or DELETE
.
Que faire alors?
Maintenant, pour désactiver le contrôle de csrf, vous pouvez créer une classe d’authentification personnalisée CsrfExemptSessionAuthentication
qui s’étend de la classe par défaut SessionAuthentication
. Dans cette classe d'authentification, nous allons écraser la vérification enforce_csrf()
qui se passait à l'intérieur de la SessionAuthentication
réelle.
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return # To not perform the csrf check previously happening
Dans votre vue, vous pouvez alors définir le authentication_classes
comme étant:
authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)
Cela devrait gérer l’erreur csrf.
Solution plus facile:
Dans views.py, utilisez les accolades CsrfExemptMixin et authentication_classes:
# 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_classes = []
def post(self, request, format=None):
return Response({'received data': request.data})
Modifier urls.py
Si vous gérez vos itinéraires dans urls.py, vous pouvez envelopper vos itinéraires souhaités avec csrf_exempt () pour les exclure du middleware de vérification 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())),
...
)
Sinon, en tant que décorateur, l'utilisation du décorateur @csrf_exempt peut mieux convenir à leurs besoins.
par exemple,
from Django.views.decorators.csrf import csrf_exempt
from Django.http import HttpResponse
@csrf_exempt
def my_view(request):
return HttpResponse('Hello world')
devrait faire le travail!
Si vous ne souhaitez pas utiliser l'authentification basée sur la session, vous pouvez supprimer Session Authentication
de REST_AUTHENTICATION_CLASSES, ce qui éliminerait automatiquement tous les problèmes liés au csrf. Mais dans ce cas, les apis consultables pourraient ne pas fonctionner.
Outre cette erreur ne devrait pas venir même avec l'authentification de session. Vous devez utiliser une authentification personnalisée comme TokenAuthentication pour votre apis et vous assurer d’envoyer Accept:application/json
et Content-Type:application/json
(à condition que vous utilisiez json) dans vos demandes avec un jeton d’authentification.
Pour tous ceux qui n'ont pas trouvé de réponse utile. Oui, DRF supprime automatiquement la protection CSRF si vous n'utilisez pas SessionAuthentication
AUTHENTICATION CLASS, par exemple, de nombreux développeurs n'utilisent que JWT:
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
Mais le problème CSRF not set
peut être dû à une autre raison, par exemple si vous n'avez pas correctement ajouté le chemin d'accès à votre vue:
url(r'^api/signup/', CreateUserView), # <= error! DRF cant remove CSRF because it is not as_view that does it!
au lieu de
url(r'^api/signup/', CreateUserView.as_view()),
Je suis frappé du même problème. J'ai suivi ceci référence et cela a fonctionné. La solution est de créer un middleware
Ajoutez le fichier disable.py dans l'une de vos applications (dans mon cas, il s'agit de "myapp")
class DisableCSRF(object):
def process_request(self, request):
setattr(request, '_dont_enforce_csrf_checks', True)
Et ajoutez le logiciel intermédiaire au MIDDLEWARE_CLASSES
MIDDLEWARE_CLASSES = (
myapp.disable.DisableCSRF,
)
J'ai essayé quelques-unes des réponses ci-dessus et je pensais que créer un cours séparé était un peu excessif.
Pour référence, j'ai rencontré ce problème lors de la tentative de mise à jour d'une méthode de vue basée sur une fonction vers une méthode de vue basée sur une classe pour l'enregistrement de l'utilisateur.
Lorsque vous utilisez des vues basées sur des classes (CBV) et Django Rest Framework (DRF), héritez de la classe ApiView et définissez permission_classes et authentication_classes sur un tuple vide. Trouvez un exemple ci-dessous.
class UserRegistrationView(APIView):
permission_classes = ()
authentication_classes = ()
def post(self, request, *args, **kwargs):
# rest of your code here
Si vous utilisez un environnement virtuel exclusif pour votre application, vous pouvez utiliser l’approche suivante sans appliquer d’autres applications.
Ce que vous avez observé se produit parce que rest_framework/authentication.py
a ce code dans la méthode authenticate
de SessionAuthentication
classe:
self.enforce_csrf(request)
Vous pouvez modifier la classe Request
pour avoir une propriété appelée csrf_exempt
et l'initialiser à l'intérieur de votre classe View respective sur True
si vous ne souhaitez pas de contrôles CSRF. Par exemple:
Ensuite, modifiez le code ci-dessus comme suit:
if not request.csrf_exempt:
self.enforce_csrf(request)
Il y a quelques modifications connexes à faire dans la classe Request
. Une implémentation complète est disponible ici (avec une description complète): https://github.com/piaxis/Django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed
Ma solution est montré coup. Juste décorer ma classe.
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