web-dev-qa-db-fra.com

Django Rest Framework supprime le fichier csrf

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?

89
Irene Texas

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.

185
Rahul Gupta

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})
15
bixente57

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!

11
Syed Faizan

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.

8
hspandher

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()),
8
user3479125

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,
)
3
Venkatesh Mondi

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
2
Mike Hawes

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

1
Reetesh Ranjan

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
1
Jak Liao