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ò far inviare i tuoi moduli dal browser di un visitatore. Un programma non dispone di una pagina del genere né di un token.
@csrf_exempt, da django.views.decorators.csrf, disattiva il controllo per una singola vista:
@csrf_exempt
def webhook(request):
...Questo comporta una rinuncia: ora qualsiasi sito web può far inviare questo POST dal browser di un visitatore. Va bene per una vista che non dipende da chi ha effettuato l'accesso, come l'elenco delle attività. Un'API che agisce come utente autenticato 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:
POST /api/tasks/funziona senza token.- Solo
task_listè esente.
Premi Run, poi digita questo nella scheda Shell. Prima della modifica stampa 403, dopo 201: 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