CSRF ו-API
חלק מהיחידה ממשקי API של JSON במסלול ה-Django של Coddy. שיעור 6 מתוך 19.
תוכנית אמיתית ששולחת POST /api/tasks/ מקבלת 403 אסור. הגנת CSRF של Django דורשת שכל בקשת POST תכלול אסימון סודי מאחד הדפים שלך, כדי שאתר אחר לא יוכל לגרום לדפדפן של מבקר לשלוח את הטפסים שלך. לתוכנית אין דף כזה ואין לה אסימון.
@csrf_exempt, מתוך django.views.decorators.csrf, משבית את הבדיקה עבור תצוגה אחת:
@csrf_exempt
def webhook(request):
...יש לכך מחיר: כל אתר יכול כעת לגרום לדפדפן של מבקר לשלוח את בקשת ה-POST הזאת. זה בסדר עבור תצוגה שאינה תלויה בזהות המשתמש המחובר, כמו רשימת המשימות. API שפועל בשם המשתמש המחובר משאיר את הגנת CSRF פעילה, והסקריפט שבדף שלו שולח את האסימון בכותרת X-CSRFToken.
אתגר
בינוניאפשר לתוכניות ליצור משימות ללא אסימון CSRF:
POST /api/tasks/פועל ללא אסימון.- רק
task_listמוחרגת.
לחצו על Run, ואז הקלידו זאת בכרטיסייה Shell. לפני השינוי יודפס 403, ואחריו 201: from django.test import Client; print(Client(enforce_csrf_checks=True).post("/api/tasks/", {"title": "Pay rent"}, content_type="application/json").status_code)
נסו בעצמכם
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))
כל השיעורים ביחידה ממשקי API של JSON
תרגלו בעצמכם: Django אונליין