Menu
CoddyTech

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.

challenge icon

Sfida

Medio

Consenti 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

Esercitati da solo: Playground Django