CSRF et API
Fait partie de la section API JSON du Journey Django de Coddy. Leçon 6 sur 19.
Un véritable programme qui envoie POST /api/tasks/ reçoit une réponse 403 Forbidden. La protection CSRF de Django exige que chaque POST transporte un jeton secret provenant de l’une de vos propres pages, afin qu’un autre site web ne puisse pas faire soumettre vos formulaires par le navigateur d’un visiteur. Un programme ne dispose ni d’une telle page ni d’un jeton.
@csrf_exempt, provenant de django.views.decorators.csrf, désactive la vérification pour une vue :
@csrf_exempt
def webhook(request):
...Mais cela implique un compromis : n’importe quel site web peut désormais faire envoyer cette requête POST par le navigateur d’un visiteur. Cela convient à une vue qui ne dépend pas de l’identité de l’utilisateur connecté, comme la liste des tâches. Une API qui agit au nom de l’utilisateur connecté conserve la protection CSRF activée, et le script de sa page envoie le jeton dans un en-tête X-CSRFToken.
Défi
MoyenPermettez aux programmes de créer des tâches sans jeton CSRF :
POST /api/tasks/fonctionne sans jeton.- Seul
task_listest exempté.
Cliquez sur Exécuter, puis saisissez ceci dans l’onglet Shell. Avant la modification, cela affiche 403 ; après, 201 : from django.test import Client; print(Client(enforce_csrf_checks=True).post("/api/tasks/", {"title": "Pay rent"}, content_type="application/json").status_code)
Essayez vous-même
import json
from django.http import JsonResponse
from django.shortcuts import render
from .models import Task
def task_to_dict(task):
return {
"id": task.id,
"title": task.title,
"done": task.done,
"priority": task.priority,
}
def home(request):
return render(request, "tasks/home.html", {"tasks": Task.objects.all()})
def stats(request):
data = {
"total": Task.objects.count(),
"done": Task.objects.filter(done=True).count(),
}
return JsonResponse(data)
def task_list(request):
if request.method == "POST":
data = json.loads(request.body)
task = Task.objects.create(
title=data["title"],
priority=data.get("priority", "normal"),
)
return JsonResponse(task_to_dict(task), status=201)
tasks = Task.objects.all()
done = request.GET.get("done")
if done == "true":
tasks = tasks.filter(done=True)
elif done == "false":
tasks = tasks.filter(done=False)
return JsonResponse([task_to_dict(task) for task in tasks], safe=False)
def task_detail(request, pk):
task = Task.objects.filter(pk=pk).first()
if task is None:
return JsonResponse({"error": "Task not found"}, status=404)
return JsonResponse(task_to_dict(task))
Toutes les leçons de API JSON
2Lire les requêtes
Filtrer avec une requêteCréer avec POST5Projet : Trier le travail
Projet : Les prioritésProjet : Effacer les tâches terminéesEntraînez-vous par vous-même : Playground Django