Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Parolni hech qachon ochiq saqlamang
- 2.2. JWT nima
- 2.3. Token yaratish va tekshirish
- 2.4. Login endpoint
- 2.5. OAuth2PasswordBearer bilan token olish
- 2.6. joriy_foydalanuvchi bog'liqligi
- 2.7. Token muddati (exp)
- 2.8. Xato holatlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Parol hash va token
- Misol 2 — Token xato holatlari
- Misol 3 — Login va himoyalangan endpoint
- Misol 4 — Amaliy: to'liq auth tizimi
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
20.10-dars: Autentifikatsiya — JWT
20-QISM — WEB-BACKEND (FastAPI) · 10-dars
1. Kirish va motivatsiya
CRUD API tayyor, lekin hamma hamma narsani qila oladi — istalgan odam kurs o'chira oladi. Real API foydalanuvchini tanishi (autentifikatsiya) kerak: kim so'rov yuboryapti? U tizimga kirganmi? Bu darsda autentifikatsiya — foydalanuvchini tanishni o'rganamiz.
Zamonaviy API'lar JWT (JSON Web Token) ishlatadi. Foydalanuvchi login/parol bilan bir marta kiradi, server unga token (imzolangan ma'lumot) beradi. Keyingi har so'rovda foydalanuvchi tokenni yuboradi — server uni tekshiradi (bazaga qaramasdan). Token — "kirish chiptasi": bir marta olinadi, ko'p marta ishlatiladi.
Real vaziyat. Bir API har so'rovda login/parolni so'rardi — mijoz ilovasi parolni saqlab, har so'rovga qo'shishga majbur edi (xavfli). Va har so'rovda parol bazada tekshirilardi (sekin, parol hash'i har safar hisoblanardi). Jamoa JWT'ga o'tdi: bir marta login → token, keyingi so'rovlar token bilan. Parol faqat bir marta uzatildi, token bazasiz tekshirildi (imzo orqali). Xavfsizlik va tezlik oshdi.
Bu darsda JWT autentifikatsiyani — parol hash, token yaratish/tekshirish va himoyalashni o'rganamiz.
Bu darsda:
- Parol hash (bcrypt — parolni hech qachon ochiq saqlamang)
- JWT token (yaratish, tekshirish)
- Login endpoint (
OAuth2PasswordRequestForm) OAuth2PasswordBearerbilan token olishjoriy_foydalanuvchibog'liqligi- Token muddati (
exp) - Xato holatlar (401)
- Amaliy: to'liq auth tizimi
ℹ Misollarda FastAPI
TestClient,PyJWTvabcryptbilan sinaladi.
2. Nazariya — chuqur tushuntirish
2.1. Parolni hech qachon ochiq saqlamang
Parollar bazada hash ko'rinishida saqlanadi (hech qachon ochiq matn):
import bcrypt
def hash_parol(parol: str) -> str:
return bcrypt.hashpw(parol.encode(), bcrypt.gensalt()).decode()
def tekshir_parol(parol: str, hash_: str) -> bool:
return bcrypt.checkpw(parol.encode(), hash_.encode())| Amal | Natija |
|---|---|
hashpw |
Parol → hash ($2b$12$...) |
checkpw |
Parol hash'ga mos keladimi |
gensalt |
Tasodifiy "tuz" (salt) |
Hash — bir tomonlama: paroldan hash olinadi, lekin hash'dan parol tiklanmaydi. bcrypt sekin (ataylab) — brute-force'ni qiyinlashtiradi. Baza o'g'irlansa ham parollar xavfsiz.
2.2. JWT nima
JWT — imzolangan, o'z ichida ma'lumot saqlovchi token. Uch qismdan iborat (nuqta bilan):
xxxxx.yyyyy.zzzzz
│ │ └── imzo (signature)
│ └── ma'lumot (payload: sub, exp, ...)
└── sarlavha (header: algoritm)| Qism | Ma'no |
|---|---|
| Header | Algoritm (HS256) |
| Payload | Ma'lumot (sub — kim, exp — muddat) |
| Signature | Imzo (maxfiy kalit bilan) |
JWT — o'zini tasdiqlovchi: imzo maxfiy kalit bilan yaratiladi. Kim payload'ni o'zgartirsa, imzo mos kelmaydi. Server bazaga qaramasdan tokenni tekshiradi.
2.3. Token yaratish va tekshirish
import jwt # PyJWT
import datetime
SIR = "maxfiy-kalit" # .env'da saqlanadi!
ALGO = "HS256"
def token_yarat(ism: str) -> str:
payload = {
"sub": ism,
"exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=30),
}
return jwt.encode(payload, SIR, algorithm=ALGO)
def token_oqi(token: str) -> dict:
return jwt.decode(token, SIR, algorithms=[ALGO]) # imzo + muddat tekshiriladi jwt.encode — payload'ni imzolab token yaratadi; jwt.decode — imzo va muddatni tekshiradi (xato bo'lsa PyJWTError). Maxfiy kalit — .envda (kodda emas!).
2.4. Login endpoint
Foydalanuvchi login/parol bilan token oladi:
from fastapi.security import OAuth2PasswordRequestForm
@app.post("/token")
def kirish(form: Annotated[OAuth2PasswordRequestForm, Depends()]):
user = FOYDALANUVCHILAR.get(form.username)
if not user or not tekshir_parol(form.password, user["parol_hash"]):
raise HTTPException(status_code=401, detail="login yoki parol xato")
return {"access_token": token_yarat(user["ism"]), "token_type": "bearer"} OAuth2PasswordRequestForm — standart login formasi (username, password). Parol to'g'ri bo'lsa token qaytaradi; xato bo'lsa 401. Javob {"access_token": ..., "token_type": "bearer"}.
2.5. OAuth2PasswordBearer bilan token olish
Himoyalangan endpoint tokenni Authorization: Bearer <token> sarlavhasidan oladi:
from fastapi.security import OAuth2PasswordBearer
oauth2 = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/men")
def men(token: Annotated[str, Depends(oauth2)]):
... # token — sarlavhadan olindi OAuth2PasswordBearer — Authorization: Bearer <token> sarlavhasidan tokenni oladi. Token yo'q bo'lsa avtomatik 401. tokenUrl — login endpoint (hujjat uchun).
2.6. joriy_foydalanuvchi bog'liqligi
Tokenni foydalanuvchiga aylantiruvchi bog'liqlik 20.7-bob:
def joriy_foydalanuvchi(token: Annotated[str, Depends(oauth2)]):
try:
payload = token_oqi(token)
except jwt.PyJWTError:
raise HTTPException(status_code=401, detail="token yaroqsiz")
return FOYDALANUVCHILAR[payload["sub"]]
@app.get("/men")
def men(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
return {"ism": user["ism"]} joriy_foydalanuvchi — token o'qib, foydalanuvchini qaytaradi (yoki 401). Har himoyalangan endpoint uni Depends bilan ishlatadi — auth mantigi bir joyda.
2.7. Token muddati (exp)
Token abadiy emas — exp (expiration) bilan muddat beriladi:
"exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=30)| Holat | Natija |
|---|---|
| Muddat ichida | Qabul qilinadi |
| Muddat o'tgan | ExpiredSignatureError → 401 |
exp — token qachon eskirishini belgilaydi. jwt.decode muddat o'tgan bo'lsa ExpiredSignatureError beradi. Qisqa muddat (30 daqiqa) — o'g'irlangan token ko'p zarar bermaydi.
2.8. Xato holatlar
Auth turli xatolarni 401 bilan boshqaradi:
| Xato | Sabab |
|---|---|
| Parol xato | Login noto'g'ri |
| Token yo'q | Sarlavha berilmagan |
| Token buzuq | InvalidTokenError |
| Imzo noto'g'ri | InvalidSignatureError |
| Muddat o'tgan | ExpiredSignatureError |
Barcha auth xatolari 401 Unauthorized. jwt.PyJWTError — barcha JWT xatolarining asosiy klassi (ularni birga ushlash). Xato xabari umumiy bo'lsin ("token yaroqsiz") — hujumchiga ma'lumot bermang.
3. Tez ma'lumotnoma
import jwt, bcrypt, datetime
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
# parol:
bcrypt.hashpw(parol.encode(), bcrypt.gensalt()).decode() # hash
bcrypt.checkpw(parol.encode(), hash_.encode()) # tekshir
# token:
jwt.encode({"sub": ism, "exp": ...}, SIR, algorithm="HS256") # yaratish
jwt.decode(token, SIR, algorithms=["HS256"]) # o'qish
# login:
oauth2 = OAuth2PasswordBearer(tokenUrl="token")
@app.post("/token")
def kirish(form: Annotated[OAuth2PasswordRequestForm, Depends()]): ...
# himoya:
def joriy_foydalanuvchi(token: Annotated[str, Depends(oauth2)]): ...Auth oqimi
1. login/parol → POST /token → token
2. token'ni saqlash (mijoz)
3. har so'rovda: Authorization: Bearer <token>
4. server: token tekshir → foydalanuvchi4. Batafsil misollar
Misollarda FastAPI
TestClient,PyJWTvabcryptbilan sinaladi.
Misol 1 — Parol hash va token
"""bcrypt bilan parol hash va tekshirish (bir tomonlama); JWT token yaratish va o'qish; token 3 qismli; payload."""
import warnings
warnings.filterwarnings("ignore")
import datetime
import bcrypt
import jwt
SIR = "namuna-maxfiy-kalit"
ALGO = "HS256"
def hash_parol(parol: str) -> str:
return bcrypt.hashpw(parol.encode(), bcrypt.gensalt()).decode()
def tekshir_parol(parol: str, hash_: str) -> bool:
return bcrypt.checkpw(parol.encode(), hash_.encode())
def token_yarat(ism: str) -> str:
payload = {
"sub": ism,
"exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=30),
}
return jwt.encode(payload, SIR, algorithm=ALGO)
def main() -> None:
print("=== 1. Parol hash (bir tomonlama) ===")
h = hash_parol("sirli123")
print(f" hash boshi: {h[:7]} (bcrypt belgisi)")
print(f" hash uzunligi: {len(h)}")
print("\n=== 2. Parol tekshirish ===")
print(f" to'g'ri parol: {tekshir_parol('sirli123', h)}")
print(f" xato parol: {tekshir_parol('boshqa', h)}")
print("\n=== 3. Token yaratish ===")
token = token_yarat("ali")
print(f" token qismlari (nuqta bilan): {len(token.split('.'))}")
print("\n=== 4. Token o'qish (payload) ===")
payload = jwt.decode(token, SIR, algorithms=[ALGO])
print(f" sub (kim): {payload['sub']}")
print(f" exp bor: {'exp' in payload}")
print(" ⭐ parol — hash (bir tomonlama); token — imzolangan ma'lumot")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Parol hash (bir tomonlama) ===
hash boshi: $2b$12$ (bcrypt belgisi)
hash uzunligi: 60
=== 2. Parol tekshirish ===
to'g'ri parol: True
xato parol: False
=== 3. Token yaratish ===
token qismlari (nuqta bilan): 3
=== 4. Token o'qish (payload) ===
sub (kim): ali
exp bor: True
⭐ parol — hash (bir tomonlama); token — imzolangan ma'lumotNima ko'rsatdi: 2.1, 2.2, 2.3-bo'limlar.
Misol 2 — Token xato holatlari
"""imzo tekshiruvi (noto'g'ri kalit → InvalidSignatureError); muddat (o'tgan → ExpiredSignatureError); buzuq token; PyJWTError."""
import warnings
warnings.filterwarnings("ignore")
import datetime
import jwt
SIR = "to'g'ri-kalit"
ALGO = "HS256"
def main() -> None:
print("=== 1. To'g'ri token o'qiladi ===")
token = jwt.encode({"sub": "ali"}, SIR, algorithm=ALGO)
print(f" decode → sub={jwt.decode(token, SIR, algorithms=[ALGO])['sub']}")
print("\n=== 2. ⚠️ Noto'g'ri imzo (boshqa kalit) ===")
try:
jwt.decode(token, "yolgon-kalit", algorithms=[ALGO])
except jwt.InvalidSignatureError:
print(" InvalidSignatureError — imzo mos kelmadi")
print("\n=== 3. ⚠️ Muddati o'tgan token ===")
eski = jwt.encode(
{"sub": "ali", "exp": datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc)},
SIR, algorithm=ALGO,
)
try:
jwt.decode(eski, SIR, algorithms=[ALGO])
except jwt.ExpiredSignatureError:
print(" ExpiredSignatureError — token eskirgan")
print("\n=== 4. ⚠️ Buzuq token ===")
try:
jwt.decode("bu.buzuq.token", SIR, algorithms=[ALGO])
except jwt.PyJWTError as e:
print(f" PyJWTError — {type(e).__name__} (barcha JWT xatolari asosi)")
print(" ⭐ imzo/muddat/format tekshiriladi; PyJWTError — umumiy asos")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. To'g'ri token o'qiladi ===
decode → sub=ali
=== 2. ⚠️ Noto'g'ri imzo (boshqa kalit) ===
InvalidSignatureError — imzo mos kelmadi
=== 3. ⚠️ Muddati o'tgan token ===
ExpiredSignatureError — token eskirgan
=== 4. ⚠️ Buzuq token ===
PyJWTError — DecodeError (barcha JWT xatolari asosi)
⭐ imzo/muddat/format tekshiriladi; PyJWTError — umumiy asosNima ko'rsatdi: 2.2, 2.7, 2.8-bo'limlar.
Misol 3 — Login va himoyalangan endpoint
"""login endpoint (OAuth2PasswordRequestForm); token qaytarish; OAuth2PasswordBearer; joriy_foydalanuvchi bog'liqligi; 401."""
import warnings
warnings.filterwarnings("ignore")
import datetime
from typing import Annotated
import bcrypt
import jwt
from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.testclient import TestClient
SIR = "namuna-kalit"
ALGO = "HS256"
app = FastAPI()
oauth2 = OAuth2PasswordBearer(tokenUrl="token")
def _hash(p: str) -> str:
return bcrypt.hashpw(p.encode(), bcrypt.gensalt()).decode()
FOYDALANUVCHILAR = {
"ali": {"ism": "ali", "parol_hash": _hash("sirli123"), "rol": "admin"},
}
@app.post("/token")
def kirish(form: Annotated[OAuth2PasswordRequestForm, Depends()]):
user = FOYDALANUVCHILAR.get(form.username)
if not user or not bcrypt.checkpw(form.password.encode(), user["parol_hash"].encode()):
raise HTTPException(status_code=401, detail="login yoki parol xato")
payload = {
"sub": user["ism"],
"exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=30),
}
return {"access_token": jwt.encode(payload, SIR, algorithm=ALGO), "token_type": "bearer"}
def joriy_foydalanuvchi(token: Annotated[str, Depends(oauth2)]):
try:
payload = jwt.decode(token, SIR, algorithms=[ALGO])
except jwt.PyJWTError:
raise HTTPException(status_code=401, detail="token yaroqsiz")
return FOYDALANUVCHILAR[payload["sub"]]
@app.get("/men")
def men(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
return {"ism": user["ism"], "rol": user["rol"]}
def main() -> None:
client = TestClient(app)
print("=== 1. Login (to'g'ri) ===")
javob = client.post("/token", data={"username": "ali", "password": "sirli123"})
print(f" status {javob.status_code}, token_type: {javob.json()['token_type']}")
token = javob.json()["access_token"]
print("\n=== 2. Himoyalangan endpoint (token bilan) ===")
javob = client.get("/men", headers={"Authorization": f"Bearer {token}"})
print(f" /men → status {javob.status_code}, {javob.json()}")
print("\n=== 3. ⚠️ Tokensiz ===")
print(f" /men (tokensiz) → status {client.get('/men').status_code}")
print("\n=== 4. ⚠️ Xato login ===")
javob = client.post("/token", data={"username": "ali", "password": "xato"})
print(f" xato parol → status {javob.status_code}, {javob.json()['detail']}")
print(" ⭐ login → token; har so'rov: Authorization: Bearer <token>")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Login (to'g'ri) ===
status 200, token_type: bearer
=== 2. Himoyalangan endpoint (token bilan) ===
/men → status 200, {'ism': 'ali', 'rol': 'admin'}
=== 3. ⚠️ Tokensiz ===
/men (tokensiz) → status 401
=== 4. ⚠️ Xato login ===
xato parol → status 401, login yoki parol xato
⭐ login → token; har so'rov: Authorization: Bearer <token>Nima ko'rsatdi: 2.4, 2.5, 2.6-bo'limlar.
Misol 4 — Amaliy: to'liq auth tizimi
Ro'yxatdan o'tish (register), kirish (login) va himoyalangan resurs — to'liq auth tizimini yaratamiz. Yangi foydalanuvchi ro'yxatdan o'tadi (parol hash bilan saqlanadi), kiradi (token oladi), va himoyalangan endpointga kiradi.
"""to'liq auth: register (parol hash bilan saqlash); login (token); himoyalangan endpoint; token bilan/siz; buzuq token → 401."""
import warnings
warnings.filterwarnings("ignore")
import datetime
from typing import Annotated
import bcrypt
import jwt
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.testclient import TestClient
from pydantic import BaseModel
SIR = "namuna-maxfiy-kalit"
ALGO = "HS256"
app = FastAPI(title="Wisar Auth API")
oauth2 = OAuth2PasswordBearer(tokenUrl="token")
BAZA: dict[str, dict] = {}
class RoyxatKirish(BaseModel):
ism: str
parol: str
def token_yarat(ism: str) -> str:
payload = {
"sub": ism,
"exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=30),
}
return jwt.encode(payload, SIR, algorithm=ALGO)
@app.post("/register", status_code=201)
def royxat(kirish: RoyxatKirish):
if kirish.ism in BAZA:
raise HTTPException(status_code=400, detail="bu ism band")
BAZA[kirish.ism] = {
"ism": kirish.ism,
"parol_hash": bcrypt.hashpw(kirish.parol.encode(), bcrypt.gensalt()).decode(),
}
return {"ism": kirish.ism, "holat": "ro'yxatdan o'tdi"}
@app.post("/token")
def kirish(form: Annotated[OAuth2PasswordRequestForm, Depends()]):
user = BAZA.get(form.username)
if not user or not bcrypt.checkpw(form.password.encode(), user["parol_hash"].encode()):
raise HTTPException(status_code=401, detail="login yoki parol xato")
return {"access_token": token_yarat(user["ism"]), "token_type": "bearer"}
def joriy_foydalanuvchi(token: Annotated[str, Depends(oauth2)]):
xato = HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="token yaroqsiz")
try:
payload = jwt.decode(token, SIR, algorithms=[ALGO])
except jwt.PyJWTError:
raise xato
user = BAZA.get(payload.get("sub"))
if user is None:
raise xato
return user
@app.get("/profil")
def profil(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
return {"ism": user["ism"]}
def main() -> None:
client = TestClient(app)
print("=== 1. Ro'yxatdan o'tish ===")
javob = client.post("/register", json={"ism": "vali", "parol": "parol123"})
print(f" status {javob.status_code} → {javob.json()}")
print("\n=== 2. Kirish (login) ===")
javob = client.post("/token", data={"username": "vali", "password": "parol123"})
print(f" status {javob.status_code}, token olindi: {'access_token' in javob.json()}")
token = javob.json()["access_token"]
print("\n=== 3. Himoyalangan profil ===")
javob = client.get("/profil", headers={"Authorization": f"Bearer {token}"})
print(f" /profil → status {javob.status_code}, {javob.json()}")
print("\n=== 4. ⚠️ Xato holatlar ===")
print(f" band ism → status {client.post('/register', json={'ism': 'vali', 'parol': 'x'}).status_code}")
print(f" buzuq token → status {client.get('/profil', headers={'Authorization': 'Bearer buzuq'}).status_code}")
print(" ⭐ register (hash) → login (token) → himoyalangan resurs")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ro'yxatdan o'tish ===
status 201 → {'ism': 'vali', 'holat': "ro'yxatdan o'tdi"}
=== 2. Kirish (login) ===
status 200, token olindi: True
=== 3. Himoyalangan profil ===
/profil → status 200, {'ism': 'vali'}
=== 4. ⚠️ Xato holatlar ===
band ism → status 400
buzuq token → status 401
⭐ register (hash) → login (token) → himoyalangan resursNima ko'rsatdi: 2.1–2.8-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Parolni ochiq saqlash" | Har doim hash (bcrypt) |
| "Hash'dan parol tiklanadi" | Bir tomonlama |
| "Token — maxfiy" | Token o'qiladi (imzo himoya) |
| "JWT'da parol bo'lsin" | Hech qachon — faqat sub, exp |
| "Token abadiy" | exp — muddat bor |
| "Maxfiy kalit kodda" | .envda (git'ga emas) |
| "Har so'rovda login" | Bir marta login → token |
| "Token bazada tekshiriladi" | Imzo orqali (bazasiz) |
6. Keng tarqalgan xatolar va yechimlari
1. Parolni ochiq saqlash
BAZA[ism] = {"parol": parol} # ❌ XAVFLI
BAZA[ism] = {"parol_hash": hash_parol(parol)} # ✅2. Maxfiy kalitni kodda
SIR = "12345" # ❌ kodda/git'da
SIR = os.environ["JWT_SIR"] # ✅ .env'dan3. exp bermaslik (abadiy token)
jwt.encode({"sub": ism}, SIR, ...) # ⚠️ muddatsiz
jwt.encode({"sub": ism, "exp": ...}, ...) # ✅4. JWT'da maxfiy ma'lumot
{"sub": ism, "parol": parol} # ❌ payload o'qiladi!
{"sub": ism, "exp": ...} # ✅5. Xato xabari ko'p ma'lumot berish
raise HTTPException(401, "parol xato") # ⚠️ login bor deydi
raise HTTPException(401, "login yoki parol xato") # ✅ umumiy6. Bitta xato turini ushlash
except jwt.ExpiredSignatureError: # ⚠️ boshqalari o'tib ketadi
except jwt.PyJWTError: # ✅ barcha JWT xatolari7. algorithms ro'yxatsiz decode
jwt.decode(token, SIR) # ❌ algoritm kerak
jwt.decode(token, SIR, algorithms=["HS256"]) # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 20.6-dars (o'tilgan): sarlavhalar —
Authorization: Bearer - 20.7-dars (o'tilgan): bog'liqlik —
joriy_foydalanuvchi - 20.11-dars: ruxsatlar — kim nima qila oladi (rol)
- 20.12-dars: xatolar —
401/403boshqaruvi - 16.4-dars (o'tilgan): xavfsizlik — hash, tuz tushunchasi
8. Eng yaxshi amaliyotlar
Parolni har doim hash qiling (bcrypt) — hech qachon ochiq.
Maxfiy kalitni
.envda saqlang (git'ga emas).Token payload'iga maxfiy ma'lumot qo'ymang (o'qiladi).
expbilan token muddatini cheklang (30 daqiqa).Barcha JWT xatolarini
jwt.PyJWTErrorbilan ushlang.Auth mantiqini bog'liqlik qiling (
joriy_foydalanuvchi).Xato xabari umumiy bo'lsin (hujumchiga ma'lumot bermang).
decodedaalgorithmsni aniq bering (xavfsizlik).
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # parol qanday saqlanadi?
2. # hash bir tomonlamami?
3. # JWT necha qismdan iborat?
4. # JWT payload maxfiymi?
5. # exp nima?
6. # maxfiy kalit qayerda?
7. # login qaysi status (xato parol)?
8. # tokensiz himoyalangan endpoint?
9. # OAuth2PasswordBearer nima oladi?
10. # PyJWTError nima?
11. # token bazada tekshiriladimi?
12. # payload'ga parol qo'ysa bo'ladimi?Javoblar
- Hash (bcrypt) — ochiq emas
- Ha (hash'dan parol tiklanmaydi)
- Uch (header.payload.signature)
- Yo'q (o'qiladi; imzo himoya qiladi)
- Token muddati (expiration)
.envda (kod/git'da emas)- 401
- 401
Authorization: Bearer <token>sarlavhasidan tokenni- Barcha JWT xatolarining asosiy klassi
- Yo'q (imzo orqali, bazasiz)
- Yo'q (payload o'qiladi — maxfiy emas)
Vazifa 2: Xatolarni tuzating
1. BAZA[ism] = {"parol": parol} # saqlash
2. SIR = "12345" # kalit
3. jwt.encode({"sub": ism}, SIR, ...) # muddat
4. {"sub": ism, "parol": parol} # payload
5. except jwt.ExpiredSignatureError: # xato turiJavoblar
1. BAZA[ism] = {"parol_hash": hash_parol(parol)}
2. SIR = os.environ["JWT_SIR"]
3. jwt.encode({"sub": ism, "exp": ...}, SIR, ...)
4. {"sub": ism, "exp": ...} # maxfiy ma'lumotsiz
5. except jwt.PyJWTError: # barcha JWT xatolariVazifa 3: Register va login
To'liq auth oqimi:
POST /register(parol hash bilan)POST /token(login → token)GET /profil(himoyalangan)TestClientbilan to'liq oqim test
Vazifa 4: Token muddati
Muddat bilan ishlash:
- Qisqa muddatli token (test uchun o'tgan)
ExpiredSignatureErrorushlash → 401- Yangi token olish (refresh tushunchasi)
- Muddat holatlarini test
Vazifa 5: Parol xavfsizligi
Parol qoidalari:
field_validatorbilan parol kuchi (uzunlik, raqam, katta harf)- Ro'yxatda tekshirish
- Hash saqlash
- Zaif parol → 422 test
Vazifa 6: Xato holatlari to'plami
Barcha auth xatolarini test:
- Xato parol, band ism
- Tokensiz, buzuq token
- Muddati o'tgan token
- Noto'g'ri imzo
- Har biri to'g'ri status/xabar
Vazifa 7: O'ylash
JWT autentifikatsiya holatsiz (stateless): server tokenni imzo orqali tekshiradi, sessiya ma'lumotini saqlamaydi. Bu an'anaviy sessiya (server sessiyani xotirada/bazada saqlaydi) dan farq qiladi. Holatsiz autentifikatsiyaning afzalligi (masshtablanish) va kamchiligi (tokenni bekor qilish qiyin) nima, va bu "holat qayerda saqlanadi" tanlovi tizim dizaynida qanchalik muhim?
Javob
Qisqa javob: JWT holatsiz — sessiya ma'lumoti tokenda (mijozda), serverda emas. Server tokenni imzo orqali tekshiradi, hech narsa saqlamaydi. Afzalligi: masshtablanish — har server tokenni mustaqil tekshiradi (umumiy sessiya xotirasi kerak emas), ko'p server oson qo'shiladi. Kamchiligi: tokenni bekor qilish qiyin — token muddati tugaguncha amal qiladi (server "unut" deb ayta olmaydi, chunki hech narsa saqlamaydi). Bu "holat qayerda" tanlovi tizim dizaynining markaziy savoli.
1. Holatsiz vs holatli
| Holatli (sessiya) | Holatsiz (JWT) |
|---|---|
| Server sessiyani saqlaydi | Token o'zida ma'lumot |
| Bekor qilish oson | Bekor qilish qiyin |
| Umumiy xotira kerak | Har server mustaqil |
| Masshtablanish qiyin | Masshtablanish oson |
2. Holatsizlik afzalligi
| Afzallik | Sabab |
|---|---|
| Masshtablanish | Umumiy sessiya yo'q |
| Tezlik | Bazasiz tekshiruv |
| Oddiy server | Holat saqlamaydi |
| Mikroservis | Har xizmat mustaqil tekshiradi |
3. Holatsizlik kamchiligi
| Kamchilik | Sabab |
|---|---|
| Bekor qilish qiyin | Server "unut" ayta olmaydi |
| Yangilash murakkab | Refresh token kerak |
| Token o'g'irlansa | Muddat tugaguncha amal |
Yechim: qisqa muddat + refresh token; yoki qora ro'yxat (blacklist — holat qo'shadi).
4. "Holat qayerda" — markaziy tanlov
| Holat joyi | Ta'sir |
|---|---|
| Serverda (sessiya) | Nazorat, lekin masshtablanish qiyin |
| Mijozda (JWT) | Masshtablanish, lekin nazorat kam |
| Bazada | Ishonchli, lekin sekin |
5. Muhandislik saboqlari
- "Holat qayerda" — dizaynning asosiy savoli
- Holatsiz — masshtablanish, lekin bekor qilish qiyin
- Har tanlovda o'zaro kelishuv (trade-off)
- Kombinatsiya (JWT + refresh) — ko'p holda yechim
6. Xulosa
- JWT holatsiz — sessiya tokenda, serverda emas
- Afzallik: masshtablanish; kamchilik: bekor qilish
- Refresh token/qisqa muddat — kamchilikni yumshatadi
- "Holat qayerda" — tizim dizaynining markaziy tanlovi
Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.
Xulosa
Bu darsda JWT autentifikatsiyani — foydalanuvchini tanishni o'rgandik.
Eng muhim uch fikr:
Parol hash — xavfsizlik asosi. Parollar bazada hech qachon ochiq saqlanmaydi —
bcryptbilan hash qilinadi. Hash bir tomonlama: paroldan hash olinadi, lekin hash'dan parol tiklanmaydi.bcrypt.hashpw(yaratish) vabcrypt.checkpw(tekshirish) — parolni xavfsiz boshqaradi. Baza o'g'irlansa ham parollar himoyalangan.JWT — holatsiz token. JWT uch qismdan iborat (header.payload.signature), imzo maxfiy kalit bilan yaratiladi.
jwt.encodetokenni imzolaydi,jwt.decodeimzo va muddat (exp) ni tekshiradi. Token o'qiladi (maxfiy emas) — shuning uchun payload'iga parol yoki maxfiy ma'lumot qo'yilmaydi, faqatsub(kim) vaexp(muddat). Maxfiy kalit.envda saqlanadi (kodda/git'da emas).Login oqimi va himoya. Foydalanuvchi
OAuth2PasswordRequestFormbilan login/parol yuboradi, to'g'ri bo'lsa token oladi. Keyingi so'rovlarAuthorization: Bearer <token>sarlavhasini yuboradi;OAuth2PasswordBearertokenni oladi,joriy_foydalanuvchibog'liqligi uni foydalanuvchiga aylantiradi (yoki401). Barcha auth xatolari (xato parol, buzuq/muddati o'tgan token, noto'g'ri imzo)401bilan boshqariladi —jwt.PyJWTErrorbarchasini birga ushlaydi.
Keyingi darsda ruxsatlar ni o'rganamiz: autentifikatsiya "kim" ni aniqladi, ruxsat esa "u nima qila oladi" ni belgilaydi — rollar (admin, oddiy), egalik tekshiruvi va Depends bilan ruxsat qatlamlari.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!