CSRF e API
Fa parte della sezione API JSON del percorso Django di Coddy. Lezione 6 di 19.
Un programma reale che invia POST /api/tasks/ riceve 403 Forbidden. La protezione CSRF di Django vuole che ogni POST includa un token segreto proveniente da una delle tue pagine, così un altro sito web non può fare in modo che il browser di un visitatore invii i tuoi moduli. Un programma non ha una pagina di questo tipo né un token.
@csrf_exempt, da django.views.decorators.csrf, disattiva il controllo per una vista:
@csrf_exempt
def webhook(request):
...Questo comporta una rinuncia: qualsiasi sito web può ora fare in modo che il browser di un visitatore invii questa richiesta POST. Va bene per una vista che non dipende da chi ha effettuato l'accesso, come l'elenco delle attività. Un'API che agisce come l'utente che ha effettuato l'accesso mantiene attiva la protezione CSRF e lo script della sua pagina invia il token in un'intestazione X-CSRFToken.
Sfida
MedioConsenti ai programmi di creare attività senza un token CSRF. In tasks/views.py, esenta dal controllo solo task_list, in modo che POST /api/tasks/ funzioni senza token.
Esegui la riga qui sotto nella scheda Shell, dove enforce_csrf_checks=True fa sì che il client di test controlli i token: stampa 201 invece di 403.
from django.test import Client; print(Client(enforce_csrf_checks=True).post("/api/tasks/", {"title": "Pay rent"}, content_type="application/json").status_code)Provalo tu
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))
Tutte le lezioni di API JSON
2Lettura delle richieste
Filtrare con una queryCreare con POST5Progetto: organizzare il lavoro
Progetto: le prioritàProgetto: cancellare le attività completateEsercitati da solo: Playground Django