Ga naar hoofdinhoud

Wie mag wat: elk endpoint apart

Een controle beschermt alleen het endpoint waar hij in staat. Het htmx-overzicht heeft ook een knop Alles wissen, met een eigen endpoint DELETE /berichten. Staat daar geen controle in, dan wist Alex daarmee alsnog het bericht van Sara, en alle andere berichten erbij.

Loop daarom elk endpoint langs dat iets verandert of verwijdert, en stel bij elk dezelfde vraag: wie mag dit? In opdracht 1 doe je dat voor Alles wissen.

Opdrachten​

Opdracht 1: Make - Alles wissen, maar alleen van jou​

Voeg een endpoint DELETE /berichten toe dat alleen de berichten van de bezoeker zelf wist. Test het met een scriptje waarin Alex alles wist, en kijk of het bericht van Sara blijft staan.

Tip

Loop niet over alle sleutels in gastenboek.db, maar over de sleutels in de sessie.

Antwoord
@app.delete("/berichten")
async def alles_wissen(sessie_id: str = Cookie(default="")):
with SqliteDict("sessies.db") as sessies:
mijn = sessies.get(sessie_id, {})
with SqliteDict("gastenboek.db") as db:
for sleutel in mijn.get("berichten", []):
if sleutel in db:
del db[sleutel]
db.commit()
return {"bericht": "Jouw berichten zijn gewist"}

Het testscript:

import httpx

adres = "http://127.0.0.1:8000"

sara = httpx.Client(base_url=adres)
alex = httpx.Client(base_url=adres)

sara.post("/bericht", data={"naam": "Sara", "bericht": "Hoi allemaal"})
alex.post("/bericht", data={"naam": "Alex", "bericht": "Leuk gastenboek"})

print(alex.delete("/berichten").json())
namen = [bericht["naam"] for bericht in alex.get("/berichten").json().values()]
print(f"Nog in het gastenboek: {namen}")

Uitvoer, met een lege database:

{'bericht': 'Jouw berichten zijn gewist'}
Nog in het gastenboek: ['Sara']

Hier is er geen 403 nodig: wie Alles wissen kiest, wist wat van hem is, en de rest blijft staan.

Opdracht 2: Predict - Een endpoint om te wijzigen​

Iemand voegt een endpoint POST /bericht/{sleutel}/wijzig toe, dat de tekst van een bericht verandert. Het heeft geen controle; bericht_verwijderen wel.

Vraag: kan Alex het bericht van Sara nu veranderen?

Antwoord

Ja. De controle in bericht_verwijderen beschermt alleen het verwijderen. Het nieuwe endpoint vraagt niet wie er komt, dus het verandert elk bericht waarvan het de sleutel krijgt. Elk endpoint dat iets verandert, heeft zijn eigen controle nodig.

Zo ziet je main.py er nu uit
import secrets
import time

from fastapi import Cookie, FastAPI, Form, HTTPException
from fastapi.responses import JSONResponse
from sqlitedict import SqliteDict

app = FastAPI()

@app.post("/bericht")
async def bericht_plaatsen(
naam: str = Form(...),
bericht: str = Form(...),
sessie_id: str = Cookie(default=""),
):
if not sessie_id:
sessie_id = secrets.token_hex(16)

sleutel = f"bericht_{time.time_ns()}"
with SqliteDict("gastenboek.db") as db:
db[sleutel] = {"naam": naam, "bericht": bericht}
db.commit()

with SqliteDict("sessies.db") as sessies:
mijn = sessies.get(sessie_id, {"naam": naam, "berichten": []})
mijn["naam"] = naam
mijn["berichten"].append(sleutel)
sessies[sessie_id] = mijn
sessies.commit()

antwoord = JSONResponse({"sleutel": sleutel})
antwoord.set_cookie(key="sessie_id", value=sessie_id, max_age=60 * 60 * 24 * 30)
return antwoord

@app.get("/berichten")
async def berichten():
with SqliteDict("gastenboek.db") as db:
return dict(db)

@app.delete("/bericht/{sleutel}")
async def bericht_verwijderen(sleutel: str, sessie_id: str = Cookie(default="")):
with SqliteDict("sessies.db") as sessies:
mijn = sessies.get(sessie_id, {})
if sleutel not in mijn.get("berichten", []):
raise HTTPException(status_code=403, detail="Dit is niet jouw bericht")

with SqliteDict("gastenboek.db") as db:
if sleutel in db:
del db[sleutel]
db.commit()
return {"bericht": "Verwijderd"}

@app.delete("/berichten")
async def alles_wissen(sessie_id: str = Cookie(default="")):
with SqliteDict("sessies.db") as sessies:
mijn = sessies.get(sessie_id, {})
with SqliteDict("gastenboek.db") as db:
for sleutel in mijn.get("berichten", []):
if sleutel in db:
del db[sleutel]
db.commit()
return {"bericht": "Jouw berichten zijn gewist"}

Elk endpoint dat iets verwijdert, controleert nu zelf.

Door naar les 5: in je eigen project.