CSRF y API
Parte de la sección API JSON del Journey de Django de Coddy. Lección 6 de 19.
Un programa real que envía POST /api/tasks/ recibe 403 Prohibido. La protección CSRF de Django exige que cada POST lleve un token secreto de una de tus propias páginas, para que otro sitio web no pueda hacer que el navegador de un visitante envíe tus formularios. Un programa no tiene esa página ni ese token.
@csrf_exempt, de django.views.decorators.csrf, desactiva la comprobación para una vista:
@csrf_exempt
def webhook(request):
...Eso implica renunciar a cierta protección: cualquier sitio web puede hacer que el navegador de un visitante envíe este POST. Está bien para una vista que no depende de quién haya iniciado sesión, como la lista de tareas. Una API que actúa como el usuario que ha iniciado sesión mantiene CSRF activado, y el script de su página envía el token en un encabezado X-CSRFToken.
Desafío
IntermedioPermite que los programas creen tareas sin un token CSRF:
POST /api/tasks/funciona sin token.- Solo
task_listestá exenta.
Pulsa Run y después escribe esto en la pestaña Shell. Antes del cambio imprime 403; despué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)
Pruébalo tú mismo
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))
Todas las lecciones de API JSON
2Lectura de solicitudes
Filtrar con una consultaCrear con POST5Proyecto: Organizar el trabajo
Proyecto: PrioridadesProyecto: Borrar las tareas completadasPractica por tu cuenta: Playground de Django