CSRF und APIs
Teil des Abschnitts JSON-APIs der Django-Journey von Coddy. Lektion 6 von 19.
Ein echtes Programm, das POST /api/tasks/ sendet, erhält 403 Zugriff verweigert. Der CSRF-Schutz von Django verlangt, dass jede POST-Anfrage ein geheimes Token von einer deiner eigenen Seiten enthält, damit eine andere Website nicht den Browser eines Besuchers dazu bringen kann, deine Formulare abzusenden. Ein Programm hat keine solche Seite und kein Token.
@csrf_exempt aus django.views.decorators.csrf schaltet die Prüfung für eine einzelne View aus:
@csrf_exempt
def webhook(request):
...Damit gibst du etwas auf: Jede Website kann nun den Browser eines Besuchers dazu bringen, diese POST-Anfrage zu senden. Das ist für eine View in Ordnung, die nicht davon abhängt, wer angemeldet ist, etwa für die Aufgabenliste. Bei einer API, die als angemeldeter Benutzer handelt, bleibt der CSRF-Schutz aktiviert, und das Skript der zugehörigen Seite sendet das Token in einem X-CSRFToken-Header.
Aufgabe
MittelLass Programme ohne CSRF-Token Aufgaben erstellen. Nimm in tasks/views.py nur task_list von der Prüfung aus, damit POST /api/tasks/ ohne Token funktioniert.
Führe die folgende Zeile im Tab „Shell“ aus. Dabei sorgt enforce_csrf_checks=True dafür, dass der Test-Client Token prüft: Die Zeile gibt 201 statt 403 aus.
from django.test import Client; print(Client(enforce_csrf_checks=True).post("/api/tasks/", {"title": "Pay rent"}, content_type="application/json").status_code)Probier es selbst
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))
Alle Lektionen in JSON-APIs
2Anfragen lesen
Mit einer Query filternMit POST erstellen5Projekt: Arbeit sortieren
Projekt: PrioritätenProjekt: Erledigte Aufgaben löschenÜbe selbstständig: Django-Playground