web-dev-qa-db-fra.com

Comment créer un JSON simple POST) à l’aide de Django REST Framework?, Jeton CSRF manquant ou incorrect

J'apprécierais que quelqu'un me montre comment faire une simple demande POST en utilisant JSON avec Django REST. Je ne vois pas des exemples de cela dans le tutoriel n'importe où?

Voici mon objet de modèle de rôle que j'aimerais poster. Ce sera un tout nouveau rôle que je voudrais ajouter à la base de données mais je reçois une erreur 500.

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

Voici ma demande curl sur une invite de terminal 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

Travaille avec une requête GET, et je peux extraire tous les rôles de la base de données, mais je n'arrive pas à créer de nouveaux rôles. Je n'ai pas d'autorisations définies. J'utilise une vue standard dans 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

Et dans mon urls.py pour cette application, les URL correspondantes - les mappages de vue sont correctes:

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

Le message d'erreur est:

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

Qu'est-ce qui se passe ici et quelle est la solution pour cela? Localhost est-il une demande intersite? J'ai ajouté @csrf_exempt à RoleDetail et RoleList mais cela ne semble rien changer. Ce décorateur peut-il même être ajouté à une classe ou doit-il être ajouté à une méthode? Ajout du @csrf_exempt décorer, mon erreur devient:

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'

Ensuite, j'ai désactivé CSRF dans l’ensemble de l’application, et j’obtiens le message suivant:

{"non_field_errors": ["Données non valides"]} lorsque mon objet JSON que je connais est un json valide. C'est une erreur hors champ, mais je suis coincé ici.

Eh bien, il s'avère que mon code secret n'était pas valide?

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

contre

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

Le fait d'avoir entre crochets [] entraîne l'échec de la demande POST. Mais l'utilisation du validateur jsonlint.com valide les deux objets json.

Update : Le problème était l'envoi du POST avec PostMan, pas dans le backend. Voir https : //stackoverflow.com/a/17508420/203312

44
user798719

Vous devrez probablement envoyer le jeton CSRF avec votre demande. Départ https://docs.djangoproject.com/fr/1.7/ref/contrib/csrf/#csrf-ajax

Mise à jour: Puisque vous avez déjà essayé d'exempter CSRF, cela pourrait peut-être vous aider (selon la version de Django que vous utilisez): https://stackoverflow.com/a/14379073/977931

10
stellarchariot

CSRF est exempté par défaut dans Django REST Framework. Par conséquent, curl POST fonctionne correctement. L'appel de demande POSTMAN a renvoyé CSRF incorrect car POSTMAN a inclus un jeton CSRF s'il se trouve dans les cookies. Vous pouvez résoudre ce problème en nettoyant les cookies.

34
Terry Lam

C'est à partir de votre REST Paramètres du framework. Dans votre settings.py fichier, votre REST_FRAMEWORK devrait avoir ce qui suit.

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

Ceci définira votre structure REST) pour utiliser l'authentification par jeton au lieu de l'authentification csrf. Et en définissant l'autorisation sur AllowAny, vous pouvez vous authentifier uniquement à l'endroit souhaité.

24
pharingee

OK, bien évidemment, je retire ce que j'ai dit. CSRF fonctionne comme prévu.

Je faisais une demande POST en utilisant un plugin chrome appelé POSTMAN. Ma demande POST échoue avec CSRF activé).

Mais une requête POST demande en utilisant

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

fonctionne bien ... Je devais enlever les accolades, c'est-à-dire [], et m'assurer qu'il y avait une barre oblique après le 's' dans les rôles, c'est-à-dire, roles /, et que csrf activé ne générait aucune erreur.

Je ne sais pas quelle est la différence entre appeler à l'aide de POSTMAN et utiliser à l'aide de curl, mais POSTMAN est exécuté dans le navigateur Web, ce qui est la plus grande différence. Cela dit, j'ai désactivé csrf pour toute la classe RoleList, mais une requête identique fonctionne avec Curl, mais échoue avec POSTMAN.

10
user798719

Pour faire le point sur l’état actuel et résumer quelques réponses:

Les requêtes AJAX effectuées dans le même contexte que l'API avec laquelle elles interagissent utilisent généralement SessionAuthentication. Cela garantit qu'une fois qu'un utilisateur est connecté, toutes les demandes effectuées par AJAX) peuvent être authentifiées à l'aide de la même authentification basée sur la session que celle utilisée pour le reste du site Web.

Les requêtes AJAX effectuées sur un site différent de l'API avec laquelle elles communiquent doivent généralement utiliser un schéma d'authentification non basé sur une session, tel que TokenAuthentication.

Par conséquent, les réponses recommandant de remplacer SessionAuthentication par TokenAuthentication peuvent résoudre le problème, mais ne sont pas nécessairement tout à fait correctes.

Pour vous protéger contre ce type d'attaques, vous devez faire deux choses:

  1. Assurez-vous que les opérations HTTP 'sûres', telles que GET, HEAD et OPTIONS ne peuvent pas être utilisées pour modifier un état côté serveur.

  2. Assurez-vous que toute opération HTTP 'non sécurisée', telle que POST, PUT, PATCH et DELETE, nécessite toujours un jeton CSRF valide. Si vous utilisez SessionAuthentication, vous devez inclure des jetons CSRF valides pour toute opération POST, PUT, PATCH ou DELETE. .

Afin de faire des requêtes AJAX, vous devez inclure un jeton CSRF dans l'en-tête HTTP , comme décrit dans le = Django documentation.

Par conséquent, il est important que csrf soit inclus dans l'en-tête, comme par exemple cette réponse suggère.

Référence: Travailler avec AJAX, CSRF & CORS, Django REST) .

4
Wtower

Comme vous l'avez dit, votre URL était

http://localhost:8000/lakesShoreProperties/roles

Postman a quelques problèmes avec localhost. Envoi du POST à 127.0.0.1:8000/your-api/endpoint à la place a fait le tour pour moi.

3
Thosse

the old Postman a un problème avec les jetons csrf car il ne fonctionne pas avec les cookies.

Je vous suggère de passer à la nouvelle version de postman , cela fonctionne avec les cookies et vous ne ferez plus face à ce problème.

1

si vous avez défini la permission AllowAny et que vous êtes confronté au problème csrf

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

puis placer suit dans le settings.py va résoudre le problème

REST_SESSION_LOGIN = False
0
navyad