Maišymas, sesijų saugykla, Manager
Pirma nauja priklausomybė (bcrypt gyvena Go komandos išplėstinėje kriptografijoje):
go get golang.org/x/crypto/bcrypt
Penki failai kaip skirtukai, priklausomybių tvarka: 00002_sessions.sql → sessions.sql → users.sql → password.go → session.go (lentelė, jos užklausos, vartotojų užklausos, kurių reikia registracijai, maišytojas, tada Manager, kuris viską suriša). Tada paleisk sqlc generate, kad naujos užklausos taptų Go.
1. db/migrations/00002_sessions.sql — sesijų saugykla. Atkreipk dėmesį, kas čia yra ir ko nėra:
token_hash TEXT NOT NULL UNIQUE, -- saugom MAIŠĄ, ne žetoną
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
expires_at TIMESTAMPTZ NOT NULL
ON DELETE CASCADE reiškia, kad ištrynus vartotoją jo sesijos pašalinamos automatiškai. token_hash yra UNIQUE (vienas žetonas → viena sesija) ir, svarbiausia, tai maiša — neapdorotas žetonas niekada neliečia duomenų bazės.
2. internal/db/queries/sessions.sql — CreateSession, GetUserBySessionToken (jungtis, kuri paverčia žetoną tiesiai į vartotoją ir filtruoja expires_at > now()) ir DeleteSession (atsijungimas, kitą pamoką). GetUserBySessionToken naudoja sqlc.embed(users), tad grąžina visą tipizuotą User.
3. internal/db/queries/users.sql (modify) — registracijai reikia dar dviejų užklausų: CreateUser (įrašymas, RETURNING *) ir GetUserByEmail (dublikatų patikra + prisijungimas, kitą pamoką). CountUsers iš 3 pamokos nepaliesta — diff yra grynas papildymas.
4. internal/auth/password.go — HashPassword / CheckPassword. Ilgio riba — įdomioji eilutė:
// MaxPasswordLen guards bcrypt's 72-byte input limit so passwords are never
// silently truncated. (A byte, not a rune, but 64 chars is plenty.)
MaxPasswordLen = 64
CheckPassword naudoja bcrypt.CompareHashAndPassword, kuris veikia pastoviu laiku — jo negalima panaudoti kaip laiko orakulo slaptažodžiui atspėti.
5. internal/session/session.go — Manager: Create (sukuria atsitiktinį žetoną, saugo jo maišą, nustato slapuką), User (slapukas → maiša → vartotojas, arba ErrNoSession), Destroy (ištrina eilutę + panaikina slapuką). cookie pagalbininke gyvena vėliavos:
HttpOnly: true, // JS jo neperskaitys — mažina XSS žetono vagystę
Secure: m.secure, // tik HTTPS produkcijoje (cfg.IsProd())
SameSite: http.SameSiteLaxMode, // siunčiamas su navigacija, ne kryžminiais POST
Create naudojamas šią pamoką (registracija); User ir Destroy — mechanizmas, kurį 5 pamoka kvies prisijungimui ir atsijungimui — parašyti dabar, nes tai viena vientisa dalis.