Wachtwoorden: wachtwoord wijzigen
Met registreren en inloggen heb je de basis, maar een gebruiker moet zijn wachtwoord ook kunnen veranderen.
Het oude wachtwoord eerst
Een nieuw wachtwoord zet je pas in de database als het oude klopt. Je server
heeft in deze reeks geen sessie: wie alleen sara meestuurt, zou anders het
wachtwoord van Sara veranderen en haar buitensluiten. Het begin is daarom
hetzelfde als bij /inloggen:
@app.post("/wijzig")
async def wijzig(naam: str = Form(...), oud: str = Form(...), nieuw: str = Form(...)):
with SqliteDict("gebruikers.db") as db:
opgeslagen = db.get(naam, NEP)
try:
ph.verify(opgeslagen, oud)
except VerifyMismatchError:
return {"bericht": "Naam of wachtwoord klopt niet"}
if opgeslagen == NEP:
return {"bericht": "Naam of wachtwoord klopt niet"}
with SqliteDict("gebruikers.db") as db:
db[naam] = ph.hash(nieuw)
db.commit()
return {"bericht": "Wachtwoord gewijzigd"}
- Regel 3-10:
Net als bij inloggen: opzoeken met de nep-hash als reserve,
ph.verifymet het oude wachtwoord, en dezelfde melding bij een onbekende naam. - Regel 11-13:
Pas als het oude wachtwoord klopt, open je de database opnieuw en bewaar je de hash van het nieuwe.
Zet dit endpoint in hetzelfde main.py als /registreer en /inloggen: het
gebruikt dezelfde imports, dezelfde ph en dezelfde NEP. Zonder de nep-hash
zou ook /wijzig met zijn snelle antwoord verraden welke namen bestaan.
Wijzigen testen
Maak een scriptje wijzig.py. Het probeert het wachtwoord van Sara eerst te
wijzigen met een fout oud wachtwoord, en daarna met het goede. Daarna logt het
in met het oude en met het nieuwe wachtwoord:
import httpx
adres = "http://127.0.0.1:8000"
wijzig = {"naam": "sara", "oud": "fout", "nieuw": "Lange-Nieuwe-Zin-7"}
print(httpx.post(adres + "/wijzig", data=wijzig).json())
wijzig["oud"] = "welkom123"
print(httpx.post(adres + "/wijzig", data=wijzig).json())
for wachtwoord in ["welkom123", "Lange-Nieuwe-Zin-7"]:
inloggen = {"naam": "sara", "wachtwoord": wachtwoord}
print(httpx.post(adres + "/inloggen", data=inloggen).json())
Zo ziet je main.py er nu uit
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
from fastapi import FastAPI, Form, HTTPException
from sqlitedict import SqliteDict
app = FastAPI()
ph = PasswordHasher()
NEP = ph.hash("niemand")
@app.post("/registreer")
async def registreer(naam: str = Form(...), wachtwoord: str = Form(...)):
with SqliteDict("gebruikers.db") as db:
if naam in db:
raise HTTPException(status_code=400, detail="Deze naam is al bezet")
db[naam] = ph.hash(wachtwoord)
db.commit()
return {"bericht": f"Welkom, {naam}"}
@app.post("/inloggen")
async def inloggen(naam: str = Form(...), wachtwoord: str = Form(...)):
with SqliteDict("gebruikers.db") as db:
opgeslagen = db.get(naam, NEP)
try:
ph.verify(opgeslagen, wachtwoord)
except VerifyMismatchError:
return {"bericht": "Naam of wachtwoord klopt niet"}
if opgeslagen == NEP:
return {"bericht": "Naam of wachtwoord klopt niet"}
return {"bericht": "Ingelogd"}
@app.post("/wijzig")
async def wijzig(naam: str = Form(...), oud: str = Form(...), nieuw: str = Form(...)):
with SqliteDict("gebruikers.db") as db:
opgeslagen = db.get(naam, NEP)
try:
ph.verify(opgeslagen, oud)
except VerifyMismatchError:
return {"bericht": "Naam of wachtwoord klopt niet"}
if opgeslagen == NEP:
return {"bericht": "Naam of wachtwoord klopt niet"}
with SqliteDict("gebruikers.db") as db:
db[naam] = ph.hash(nieuw)
db.commit()
return {"bericht": "Wachtwoord gewijzigd"}
Registreren, inloggen en wijzigen in één server. Een hash met oude instellingen blijft nog zoals hij is; dat verandert in les 10. En iedereen kan nog eindeloos wachtwoorden proberen; daar komt in les 11 een limiet op.
Er gaat iets mis
Wijzigen lukt de tweede keer niet
Je draait wijzig.py nog een keer, en krijgt:
{'bericht': 'Naam of wachtwoord klopt niet'}
{'bericht': 'Naam of wachtwoord klopt niet'}
{'bericht': 'Naam of wachtwoord klopt niet'}
{'bericht': 'Ingelogd'}
Oorzaak: de eerste keer heeft het script het wachtwoord van Sara al
veranderd. welkom123 is niet meer haar oude wachtwoord, dus /wijzig weigert.
Dit is je controle die werkt.
Oplossing: niets, Sara heeft nu Lange-Nieuwe-Zin-7. Wil je de test
opnieuw doen, gooi dan gebruikers.db weg en draai registreer.py en
wijzig.py opnieuw.
Opdrachten
Opdracht 1: Predict - Hetzelfde wachtwoord opnieuw
Sara wijzigt haar wachtwoord nog een keer, en typt bij nieuw precies
hetzelfde als bij oud: Lange-Nieuwe-Zin-7.
Vraag: staat er daarna dezelfde code bij sara in de database als ervoor?
En kan ze nog inloggen met Lange-Nieuwe-Zin-7?
Tip
Wat doet ph.hash elke keer anders? Bekijk het daarna zelf met
lees_database.py, voor en na het wijzigen.
Antwoord
Een andere code, want ph.hash maakt bij elke hash een nieuw zout. Inloggen
met Lange-Nieuwe-Zin-7 lukt nog steeds: ph.verify haalt het nieuwe zout uit
de nieuwe hash.
Door naar les 10: een oude hash bijwerken.