Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Autentifikatsiya vs ruxsat
- 2.2. Rol asosli ruxsat
- 2.3. Ruxsat bog'liqligi
- 2.4. Bog'liqlik fabrikasi
- 2.5. Egalik tekshiruvi
- 2.6. Topilmadi va taqiq tartibi
- 2.7. dependencies=[] bilan himoya
- 2.8. Ruxsat qatlamlari
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Autentifikatsiya vs ruxsat (401 vs 403)
- Misol 2 — Ruxsat bog'liqligi va fabrika
- Misol 3 — Egalik tekshiruvi
- Misol 4 — Amaliy: to'liq ruxsat 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.11-dars: Ruxsatlar
20-QISM — WEB-BACKEND (FastAPI) · 11-dars
1. Kirish va motivatsiya
O'tgan darsda autentifikatsiyani o'rgandik — server foydalanuvchini tanidi (kim u?). Lekin tanish yetarli emas: tizimga kirgan har foydalanuvchi hamma narsani qila olmasligi kerak. Oddiy o'quvchi kurs o'chira olmasligi, boshqa odamning izohini tahrirlay olmasligi kerak. Bu — ruxsat (avtorizatsiya): foydalanuvchi nima qila oladi?
Autentifikatsiya va ruxsat — ikki alohida savol:
- Autentifikatsiya 20.10-bob: "Kim sen?" — token bilan tanish.
- Ruxsat (bu dars): "Sen buni qila olasanmi?" — rol va egalik bilan tekshirish.
Real vaziyat. Bir API autentifikatsiyani to'g'ri qildi (JWT bilan), lekin ruxsatni unutdi: kirgan har kim istalgan kursni o'chira olardi, boshqaning profilini tahrirlay olardi. Bir o'quvchi (yomon niyatli) barcha kurslarni o'chirdi. Jamoa ruxsat qatlamini qo'shdi: kurs o'chirish — faqat admin; profil tahrir — faqat egasi yoki admin. Depends bilan ruxsat tekshiruvi endpointlarga qo'shildi. Endi har amal to'g'ri tekshiriladi — tanish va ruxsat ajratildi.
Bu darsda ruxsatlarni — rol, egalik va Depends bilan ruxsat qatlamlarini o'rganamiz.
Bu darsda:
- Autentifikatsiya vs ruxsat (401 vs 403)
- Rol asosli ruxsat (admin, o'quvchi)
- Ruxsat bog'liqligi (
rol_talab) - Egalik tekshiruvi (resurs egasi)
- Bog'liqlik fabrikasi (parametrli bog'liqlik)
dependencies=[]bilan himoya- Umumiy ruxsat naqshlari
- Amaliy: to'liq ruxsat tizimi
ℹ Misollarda FastAPI
TestClientbilan sinaladi.
2. Nazariya — chuqur tushuntirish
2.1. Autentifikatsiya vs ruxsat
Ikki alohida tushuncha, ikki status kod:
| Savol | Nima | Status |
|---|---|---|
| Kim sen? | Autentifikatsiya | 401 (kirmagan) |
| Buni qila olasanmi? | Ruxsat | 403 (taqiq) |
401 Unauthorized — kirmagan (token yo'q/yaroqsiz). 403 Forbidden — kirgan, lekin ruxsat yo'q (rol yetmaydi). Bu farq muhim: 401 — "kir"; 403 — "kirgansan, lekin bu senga emas".
2.2. Rol asosli ruxsat
Foydalanuvchida rol bo'ladi (admin, o'quvchi, muallif). Amal rolga bog'liq:
def joriy_foydalanuvchi(...) -> dict:
return {"ism": "ali", "rol": "oquvchi"}
@app.delete("/kurslar/{kurs_id}")
def ochir(kurs_id: int, user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
if user["rol"] != "admin":
raise HTTPException(status_code=403, detail="admin huquqi kerak")
... Rol — foydalanuvchi huquq darajasi. Amal bajarishdan oldin rol tekshiriladi; yetmasa 403. Bu — eng keng tarqalgan ruxsat naqshi (RBAC — rolga asoslangan kirish nazorati).
2.3. Ruxsat bog'liqligi
Rol tekshiruvini bog'liqlik qilib takrorni yo'qotami 20.7-bob:
def faqat_admin(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
if user["rol"] != "admin":
raise HTTPException(status_code=403, detail="admin huquqi kerak")
return user
@app.delete("/kurslar/{kurs_id}")
def ochir(kurs_id: int, user: Annotated[dict, Depends(faqat_admin)]):
... # faqat admin keladi faqat_admin — ruxsat bog'liqligi. U joriy_foydalanuvchiga tayanadi (ichma-ich, 20.7) va rolni tekshiradi. Endpoint faqat ruxsatli foydalanuvchini oladi.
2.4. Bog'liqlik fabrikasi
Turli rollar uchun parametrli bog'liqlik — fabrika (funksiya qaytaruvchi funksiya):
def rol_talab(*ruxsat_rollar: str):
def tekshir(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
if user["rol"] not in ruxsat_rollar:
raise HTTPException(status_code=403, detail="ruxsat yo'q")
return user
return tekshir
@app.delete("/kurslar/{id}", dependencies=[Depends(rol_talab("admin"))])
def ochir(id: int): ...
@app.post("/kurslar", dependencies=[Depends(rol_talab("admin", "muallif"))])
def yarat(...): ... Bog'liqlik fabrikasi — parametr olib, bog'liqlik qaytaradi. rol_talab("admin") — bir yoki bir necha rolga ruxsat. Bir fabrika, ko'p ruxsat qoidasi.
2.5. Egalik tekshiruvi
Ba'zi amal rolga emas, egalikka bog'liq (o'z profilini tahrir):
@app.delete("/postlar/{post_id}")
def ochir(post_id: int, user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
post = post_top(post_id)
if post is None:
raise HTTPException(404, "topilmadi")
if post["muallif"] != user["ism"] and user["rol"] != "admin":
raise HTTPException(403, "faqat muallif yoki admin")
...Egalik — resurs egasiga (yoki adminga) ruxsat. Bu roldan farq qiladi: "o'z resursingni tahrirlay olasan, boshqanikini yo'q". Ko'pincha rol + egalik birga ishlatiladi.
2.6. Topilmadi va taqiq tartibi
Xavfsizlik uchun tekshiruv tartibi muhim:
| Holat | Status |
|---|---|
| Kirmagan | 401 |
| Resurs yo'q | 404 |
| Ruxsat yo'q | 403 |
Ko'pincha: avval autentifikatsiya (401), keyin resurs bor-yo'qligi (404), keyin ruxsat (403). Ba'zan xavfsizlik uchun "yo'q" va "taqiq" ni birlashtirish mumkin (resurs borligini oshkor qilmaslik uchun 403 o'rniga 404).
2.7. dependencies=[] bilan himoya
Natija kerak bo'lmasa, ruxsatni dependencies bilan 20.7-bob:
@app.delete("/kurslar/{id}", dependencies=[Depends(rol_talab("admin"))])
def ochir(id: int):
... # user obyekti kerak emas, faqat tekshiruv dependencies=[...] — ruxsat tekshiruvi natijasi kerak bo'lmaganda (faqat "o'tkaz yoki taqiqla"). Endpoint tozaroq — ruxsat mantigi ajratilgan.
2.8. Ruxsat qatlamlari
Murakkab tizimda ruxsat qatlam-qatlam:
joriy_foydalanuvchi (401 — kirgan?)
→ faqat_admin (403 — admin?)
→ egalik (403 — egasi?)Ruxsat qatlamlari ichma-ich bog'liqlik bilan quriladi 20.7-bob. Har qatlam bir shartni tekshiradi. Bu toza va sinaladigan — har qatlamni alohida test qilish mumkin.
3. Tez ma'lumotnoma
from fastapi import Depends, HTTPException
from typing import Annotated
# rol tekshiruvi:
def faqat_admin(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
if user["rol"] != "admin":
raise HTTPException(403, "admin huquqi kerak")
return user
# fabrika (parametrli):
def rol_talab(*rollar: str):
def tekshir(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
if user["rol"] not in rollar:
raise HTTPException(403, "ruxsat yo'q")
return user
return tekshir
# egalik:
if resurs["egasi"] != user["ism"] and user["rol"] != "admin":
raise HTTPException(403, "ruxsat yo'q")
# ishlatish:
@app.delete("/x/{id}", dependencies=[Depends(rol_talab("admin"))])
def ochir(id: int): ...Status kodlar
401 — kirmagan (autentifikatsiya)
403 — kirgan, lekin ruxsat yo'q (avtorizatsiya)
404 — resurs topilmadi4. Batafsil misollar
Misollarda FastAPI
TestClientbilan sinaladi.
Misol 1 — Autentifikatsiya vs ruxsat (401 vs 403)
"""401 (kirmagan) vs 403 (ruxsat yo'q) farqi; rol tekshiruvi; ochiq/himoyalangan/admin endpointlar."""
import warnings
warnings.filterwarnings("ignore")
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException
from fastapi.testclient import TestClient
app = FastAPI()
FOYDALANUVCHILAR = {
"tok-admin": {"ism": "admin", "rol": "admin"},
"tok-ali": {"ism": "ali", "rol": "oquvchi"},
}
def joriy_foydalanuvchi(x_token: Annotated[str | None, Header()] = None):
if x_token not in FOYDALANUVCHILAR:
raise HTTPException(status_code=401, detail="tizimga kiring")
return FOYDALANUVCHILAR[x_token]
@app.get("/ochiq")
def ochiq():
return {"kirish": "hamma uchun"}
@app.get("/profil")
def profil(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
return {"ism": user["ism"], "rol": user["rol"]}
@app.delete("/kurslar/{kurs_id}", status_code=204)
def ochir(kurs_id: int, user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
if user["rol"] != "admin":
raise HTTPException(status_code=403, detail="admin huquqi kerak")
def main() -> None:
client = TestClient(app)
print("=== 1. Ochiq endpoint ===")
print(f" /ochiq → status {client.get('/ochiq').status_code}")
print("\n=== 2. ⚠️ Kirmagan (401) ===")
print(f" /profil (tokensiz) → status {client.get('/profil').status_code} (autentifikatsiya)")
print("\n=== 3. Kirgan, lekin ruxsat yo'q (403) ===")
javob = client.delete("/kurslar/1", headers={"X-Token": "tok-ali"})
print(f" o'quvchi o'chirmoqchi → status {javob.status_code} (avtorizatsiya)")
print("\n=== 4. Admin — ruxsat bor ===")
javob = client.delete("/kurslar/1", headers={"X-Token": "tok-admin"})
print(f" admin o'chirdi → status {javob.status_code}")
print(" ⭐ 401 — kirmagan; 403 — kirgan, lekin ruxsat yo'q")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ochiq endpoint ===
/ochiq → status 200
=== 2. ⚠️ Kirmagan (401) ===
/profil (tokensiz) → status 401 (autentifikatsiya)
=== 3. Kirgan, lekin ruxsat yo'q (403) ===
o'quvchi o'chirmoqchi → status 403 (avtorizatsiya)
=== 4. Admin — ruxsat bor ===
admin o'chirdi → status 204
⭐ 401 — kirmagan; 403 — kirgan, lekin ruxsat yo'qNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Ruxsat bog'liqligi va fabrika
"""faqat_admin bog'liqligi; rol_talab fabrikasi (parametrli); bir yoki bir necha rol; dependencies=[] bilan himoya."""
import warnings
warnings.filterwarnings("ignore")
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException
from fastapi.testclient import TestClient
app = FastAPI()
FOYDALANUVCHILAR = {
"tok-admin": {"ism": "admin", "rol": "admin"},
"tok-muallif": {"ism": "vali", "rol": "muallif"},
"tok-oquvchi": {"ism": "ali", "rol": "oquvchi"},
}
def joriy_foydalanuvchi(x_token: Annotated[str | None, Header()] = None):
if x_token not in FOYDALANUVCHILAR:
raise HTTPException(status_code=401, detail="kiring")
return FOYDALANUVCHILAR[x_token]
def rol_talab(*ruxsat_rollar: str):
def tekshir(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
if user["rol"] not in ruxsat_rollar:
raise HTTPException(status_code=403, detail=f"kerakli rol: {ruxsat_rollar}")
return user
return tekshir
@app.delete("/kurslar/{kurs_id}", status_code=204, dependencies=[Depends(rol_talab("admin"))])
def ochir(kurs_id: int):
return None
@app.post("/kurslar", status_code=201, dependencies=[Depends(rol_talab("admin", "muallif"))])
def yarat(nom: str):
return {"nom": nom}
def main() -> None:
client = TestClient(app)
print("=== 1. O'chirish — faqat admin ===")
print(f" admin → status {client.delete('/kurslar/1', headers={'X-Token': 'tok-admin'}).status_code}")
print(f" muallif → status {client.delete('/kurslar/1', headers={'X-Token': 'tok-muallif'}).status_code}")
print("\n=== 2. Yaratish — admin yoki muallif ===")
print(f" admin → status {client.post('/kurslar?nom=X', headers={'X-Token': 'tok-admin'}).status_code}")
print(f" muallif → status {client.post('/kurslar?nom=Y', headers={'X-Token': 'tok-muallif'}).status_code}")
print("\n=== 3. ⚠️ O'quvchi — ruxsat yo'q ===")
print(f" o'quvchi yaratmoqchi → status {client.post('/kurslar?nom=Z', headers={'X-Token': 'tok-oquvchi'}).status_code}")
print("\n=== 4. Fabrika kuchi ===")
print(" rol_talab('admin') va rol_talab('admin', 'muallif') — bir fabrika")
print(" ⭐ bog'liqlik fabrikasi — parametrli ruxsat qoidasi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. O'chirish — faqat admin ===
admin → status 204
muallif → status 403
=== 2. Yaratish — admin yoki muallif ===
admin → status 201
muallif → status 201
=== 3. ⚠️ O'quvchi — ruxsat yo'q ===
o'quvchi yaratmoqchi → status 403
=== 4. Fabrika kuchi ===
rol_talab('admin') va rol_talab('admin', 'muallif') — bir fabrika
⭐ bog'liqlik fabrikasi — parametrli ruxsat qoidasiNima ko'rsatdi: 2.3, 2.4, 2.7-bo'limlar.
Misol 3 — Egalik tekshiruvi
"""egalik: resurs egasi yoki admin tahrirlay oladi; boshqaning resursi 403; topilmasa 404; rol + egalik birga."""
import warnings
warnings.filterwarnings("ignore")
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException, status
from fastapi.testclient import TestClient
app = FastAPI()
FOYDALANUVCHILAR = {
"tok-admin": {"ism": "admin", "rol": "admin"},
"tok-ali": {"ism": "ali", "rol": "oquvchi"},
"tok-vali": {"ism": "vali", "rol": "oquvchi"},
}
IZOHLAR = {
1: {"id": 1, "muallif": "ali", "matn": "birinchi izoh"},
2: {"id": 2, "muallif": "vali", "matn": "ikkinchi izoh"},
}
def joriy_foydalanuvchi(x_token: Annotated[str | None, Header()] = None):
if x_token not in FOYDALANUVCHILAR:
raise HTTPException(status_code=401, detail="kiring")
return FOYDALANUVCHILAR[x_token]
@app.delete("/izohlar/{izoh_id}", status_code=status.HTTP_204_NO_CONTENT)
def ochir(izoh_id: int, user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
izoh = IZOHLAR.get(izoh_id)
if izoh is None:
raise HTTPException(status_code=404, detail="izoh topilmadi")
if izoh["muallif"] != user["ism"] and user["rol"] != "admin":
raise HTTPException(status_code=403, detail="faqat muallif yoki admin")
del IZOHLAR[izoh_id]
def main() -> None:
client = TestClient(app)
print("=== 1. Muallif o'z izohini o'chiradi ===")
javob = client.delete("/izohlar/1", headers={"X-Token": "tok-ali"})
print(f" ali → izoh 1 (o'ziniki) → status {javob.status_code}")
print("\n=== 2. ⚠️ Boshqaning izohini o'chirish (403) ===")
javob = client.delete("/izohlar/2", headers={"X-Token": "tok-ali"})
print(f" ali → izoh 2 (vali'niki) → status {javob.status_code}")
print("\n=== 3. Admin har qanday izohni o'chiradi ===")
javob = client.delete("/izohlar/2", headers={"X-Token": "tok-admin"})
print(f" admin → izoh 2 → status {javob.status_code}")
print("\n=== 4. ⚠️ Yo'q izoh (404) ===")
javob = client.delete("/izohlar/999", headers={"X-Token": "tok-ali"})
print(f" yo'q izoh → status {javob.status_code}")
print(" ⭐ egalik — o'z resursing yoki admin; boshqaniki 403")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Muallif o'z izohini o'chiradi ===
ali → izoh 1 (o'ziniki) → status 204
=== 2. ⚠️ Boshqaning izohini o'chirish (403) ===
ali → izoh 2 (vali'niki) → status 403
=== 3. Admin har qanday izohni o'chiradi ===
admin → izoh 2 → status 204
=== 4. ⚠️ Yo'q izoh (404) ===
yo'q izoh → status 404
⭐ egalik — o'z resursing yoki admin; boshqaniki 403Nima ko'rsatdi: 2.5, 2.6-bo'limlar.
Misol 4 — Amaliy: to'liq ruxsat tizimi
Rol va egalikni birlashtirgan to'liq ruxsat tizimi: o'quvchi ko'radi, muallif yaratadi va o'z resursini boshqaradi, admin hamma narsani. Har amal to'g'ri qatlamda tekshiriladi.
"""to'liq ruxsat: ko'rish (hamma kirgan), yaratish (muallif+admin), tahrir/o'chirish (egasi+admin); rol + egalik qatlamlari."""
import warnings
warnings.filterwarnings("ignore")
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException, status
from fastapi.testclient import TestClient
from pydantic import BaseModel
app = FastAPI(title="Wisar Ruxsat API")
FOYDALANUVCHILAR = {
"tok-admin": {"ism": "admin", "rol": "admin"},
"tok-vali": {"ism": "vali", "rol": "muallif"},
"tok-ali": {"ism": "ali", "rol": "oquvchi"},
}
MAQOLALAR: dict[int, dict] = {}
KEYINGI = 1
class MaqolaKirish(BaseModel):
sarlavha: str
def joriy_foydalanuvchi(x_token: Annotated[str | None, Header()] = None):
if x_token not in FOYDALANUVCHILAR:
raise HTTPException(status_code=401, detail="tizimga kiring")
return FOYDALANUVCHILAR[x_token]
def rol_talab(*rollar: str):
def tekshir(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
if user["rol"] not in rollar:
raise HTTPException(status_code=403, detail="ruxsat yo'q")
return user
return tekshir
def _maqola_va_ruxsat(maqola_id: int, user: dict) -> dict:
maqola = MAQOLALAR.get(maqola_id)
if maqola is None:
raise HTTPException(status_code=404, detail="maqola topilmadi")
if maqola["muallif"] != user["ism"] and user["rol"] != "admin":
raise HTTPException(status_code=403, detail="faqat muallif yoki admin")
return maqola
@app.get("/maqolalar")
def royxat(user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
return list(MAQOLALAR.values())
@app.post("/maqolalar", status_code=201)
def yarat(kirish: MaqolaKirish, user: Annotated[dict, Depends(rol_talab("muallif", "admin"))]):
global KEYINGI
maqola = {"id": KEYINGI, "sarlavha": kirish.sarlavha, "muallif": user["ism"]}
MAQOLALAR[KEYINGI] = maqola
KEYINGI += 1
return maqola
@app.delete("/maqolalar/{maqola_id}", status_code=status.HTTP_204_NO_CONTENT)
def ochir(maqola_id: int, user: Annotated[dict, Depends(joriy_foydalanuvchi)]):
_maqola_va_ruxsat(maqola_id, user)
del MAQOLALAR[maqola_id]
def main() -> None:
client = TestClient(app)
print("=== 1. Muallif maqola yaratadi ===")
javob = client.post("/maqolalar", json={"sarlavha": "Python"}, headers={"X-Token": "tok-vali"})
print(f" vali (muallif) → status {javob.status_code}, {javob.json()}")
print("\n=== 2. ⚠️ O'quvchi yarata olmaydi (403) ===")
javob = client.post("/maqolalar", json={"sarlavha": "X"}, headers={"X-Token": "tok-ali"})
print(f" ali (o'quvchi) → status {javob.status_code}")
print("\n=== 3. Ko'rish — har kirgan foydalanuvchi ===")
print(f" o'quvchi ro'yxat → {len(client.get('/maqolalar', headers={'X-Token': 'tok-ali'}).json())} maqola")
print("\n=== 4. O'chirish — egasi yoki admin ===")
print(f" begona (ali) → status {client.delete('/maqolalar/1', headers={'X-Token': 'tok-ali'}).status_code}")
print(f" admin → status {client.delete('/maqolalar/1', headers={'X-Token': 'tok-admin'}).status_code}")
print(" ⭐ ko'rish (kirgan), yaratish (rol), o'chirish (egalik) — qatlamlar")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Muallif maqola yaratadi ===
vali (muallif) → status 201, {'id': 1, 'sarlavha': 'Python', 'muallif': 'vali'}
=== 2. ⚠️ O'quvchi yarata olmaydi (403) ===
ali (o'quvchi) → status 403
=== 3. Ko'rish — har kirgan foydalanuvchi ===
o'quvchi ro'yxat → 1 maqola
=== 4. O'chirish — egasi yoki admin ===
begona (ali) → status 403
admin → status 204
⭐ ko'rish (kirgan), yaratish (rol), o'chirish (egalik) — qatlamlarNima ko'rsatdi: 2.1–2.8-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Autentifikatsiya yetarli" | Ruxsat ham kerak |
| "401 va 403 bir xil" | 401 kirmagan, 403 taqiq |
| "Kirgan — hamma narsa" | Rol/egalik cheklaydi |
| "Rol tekshiruvi endpoint ichida" | Bog'liqlik bilan (takrorsiz) |
| "Bir rolga bir bog'liqlik" | Fabrika — parametrli |
| "Egalik = rol" | Egalik — resurs egasiga |
| "Admin ham egalik shart" | Admin ko'pincha barchaga |
| "Ruxsatni mijoz tekshiradi" | Server tekshiradi (majburiy) |
6. Keng tarqalgan xatolar va yechimlari
1. Ruxsatni unutish
@app.delete("/kurslar/{id}")
def ochir(id: int): ... # ⚠️ hamma o'chiradi
# ✅ rol/egalik tekshiruvi2. 401 va 403 aralashtirish
raise HTTPException(401, "ruxsat yo'q") # ⚠️ kirgan-ku
raise HTTPException(403, "ruxsat yo'q") # ✅ taqiq3. Rol tekshiruvini takrorlash
if user["rol"] != "admin": raise ... # ⚠️ har endpointda
# ✅ Depends(rol_talab("admin"))4. Egalikni tekshirmaslik
def ochir(id, user): del RESURS[id] # ⚠️ boshqaniki ham
if resurs["egasi"] != user["ism"]: raise 403 # ✅5. Ruxsatni mijozda tekshirish
# frontend: if (user.rol === 'admin') showButton # ⚠️ yetarli emas
# ✅ server ham tekshirsin (majburiy)6. Admin istisnosini unutish
if resurs["egasi"] != user["ism"]: raise 403 # ⚠️ admin ham taqiq
if resurs["egasi"] != user["ism"] and user["rol"] != "admin": raise 403 # ✅7. Tekshiruv tartibi (404 vs 403)
# avval resurs bor-yo'qligi (404), keyin ruxsat (403)
if resurs is None: raise 404
if not ruxsat: raise 403 # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 20.7-dars (o'tilgan): bog'liqlik — ruxsat bog'liqligi, fabrika
- 20.10-dars (o'tilgan): autentifikatsiya —
joriy_foydalanuvchi - 20.12-dars: xatolar —
401/403boshqaruvi - 21-qism (Django): ruxsat tizimi (permissions)
- 20.15-dars: testlash — ruxsat holatlarini test
8. Eng yaxshi amaliyotlar
Autentifikatsiya (401) va ruxsatni (403) ajrating.
Rol tekshiruvini bog'liqlik qiling (
rol_talab).Turli rollar uchun bog'liqlik fabrikasi.
Egalik tekshiruvida admin istisnosini qo'shing.
Ruxsatni har doim serverda tekshiring (mijoz — faqat UI).
dependencies=[]— natija kerak bo'lmaganda.Tekshiruv tartibi: 401 → 404 → 403.
Ruxsat qatlamlarini alohida test qiling.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # autentifikatsiya vs ruxsat farqi?
2. # 401 nima?
3. # 403 nima?
4. # rol nima?
5. # rol_talab fabrikasi nima qaytaradi?
6. # egalik tekshiruvi nima?
7. # admin istisnosi nima?
8. # ruxsatni kim tekshiradi?
9. # dependencies=[] qachon?
10. # tekshiruv tartibi (401/404/403)?
11. # kirgan — hamma narsani qiladimi?
12. # rol tekshiruvini qayerda?Javoblar
- Autentifikatsiya — kim; ruxsat — nima qila oladi
- Kirmagan (token yo'q/yaroqsiz)
- Kirgan, lekin ruxsat yo'q (taqiq)
- Foydalanuvchi huquq darajasi (admin, o'quvchi)
- Bog'liqlik (funksiya) qaytaradi
- Resurs egasiga (yoki admin) ruxsat
- Admin egalikdan qat'i nazar ruxsat
- Server (majburiy) — mijoz faqat UI
- Natija kerak bo'lmaganda (faqat tekshiruv)
- 401 (kirgan?) → 404 (bor?) → 403 (ruxsat?)
- Yo'q (rol/egalik cheklaydi)
- Bog'liqlikda (takrorsiz)
Vazifa 2: Xatolarni tuzating
1. @app.delete("/kurslar/{id}")
def ochir(id): ... # ruxsat yo'q
2. raise HTTPException(401, "taqiq") # kirgan-ku
3. if user["rol"] != "admin": raise ... # har endpointda
4. def ochir(id, user):
del RESURS[id] # egalik?
5. if resurs["egasi"] != user["ism"]: raise 403 # admin?Javoblar
1. @app.delete("/kurslar/{id}", dependencies=[Depends(rol_talab("admin"))])
2. raise HTTPException(403, "ruxsat yo'q")
3. # Depends(rol_talab("admin")) — bog'liqlik
4. if resurs["egasi"] != user["ism"] and user["rol"] != "admin":
raise HTTPException(403, ...)
5. if resurs["egasi"] != user["ism"] and user["rol"] != "admin":
raise HTTPException(403, ...)Vazifa 3: Rol tizimi
Uch rolli API:
- Rollar: admin, muharrir, o'quvchi
rol_talabfabrikasi- Har rol o'z amallariga
TestClientbilan har rol test
Vazifa 4: Egalik va rol birga
Blog API:
- Maqola yaratish (muallif+)
- Tahrir/o'chirish (egasi yoki admin)
- Ko'rish (hamma kirgan)
- Har holatni test
Vazifa 5: Ruxsat matritsasi
Ruxsat jadvalini amalga oshiring:
- Amallar × rollar matritsasi
- Har katak — ruxsat bor/yo'q
- Markazlashgan ruxsat funksiyasi
- To'liq test
Vazifa 6: Xavfsizlik tartibi
Tekshiruv tartibini sinang:
- 401 → 404 → 403 tartibi
- Resurs borligini yashirishni (403 o'rniga 404)
- Har tartib holati
- Qaysi tartib qachon to'g'ri — hujjatlang
Vazifa 7: O'ylash
Ruxsat tekshiruvi har doim serverda bo'lishi kerak — mijozda (frontend) tekshiruv faqat qulaylik (tugmani yashirishi), xavfsizlik emas. Foydalanuvchi brauzer kodini chetlab o'tib, to'g'ridan API'ga so'rov yubora oladi. "Mijozga ishonma" (never trust the client) tamoyili nima uchun xavfsizlikning asosi, va bu tamoyilni buzgan tizim (faqat frontend'da tekshirgan) qanday hujumga ochiq bo'ladi?
Javob
Qisqa javob: Mijoz (brauzer, mobil ilova) — foydalanuvchi nazoratida. U kodni o'zgartira, so'rovni qo'lda yubora, tekshiruvni chetlab o'ta oladi. Shuning uchun frontend'dagi ruxsat tekshiruvi — faqat qulaylik (foydalanuvchiga keraksiz tugmani ko'rsatmaslik), xavfsizlik emas. Xavfsizlik serverda bo'lishi shart, chunki server foydalanuvchi nazoratida emas. "Mijozga ishonma" — har kirgan ma'lumot (so'rov, parametr, token) tekshirilishi kerak. Faqat frontend'da tekshirgan tizim — hujumchi API'ga to'g'ridan so'rov yuborib, barcha himoyani chetlab o'tadi.
1. Mijoz nazoratda emas
| Mijoz (ishonsiz) | Server (ishonchli) |
|---|---|
| Foydalanuvchi nazoratida | Sizning nazoratingizda |
| Kod o'zgartiriladi | O'zgartirib bo'lmaydi |
| So'rov soxtalashtiriladi | So'rovni tekshiradi |
2. Frontend tekshiruvi — qulaylik
Frontend'da if (rol === 'admin') showButton — foydalanuvchi uchun qulay (keraksiz tugma yashirinadi), lekin himoya emas: hujumchi tugmasiz ham API'ga so'rov yubora oladi.
3. Faqat frontend tekshirgan tizim — hujum
1. Frontend: admin tugmasini yashiradi (o'quvchiga)
2. Hujumchi: brauzer konsolidan to'g'ridan DELETE /kurslar/1 yuboradi
3. Server tekshirmaydi → o'chiriladi (himoya chetlab o'tildi)4. "Mijozga ishonma" tamoyili
| Ishonsiz manba | Server tekshiruvi |
|---|---|
| So'rov tanasi | Validatsiya (Pydantic) |
| Parametrlar | Tekshiruv |
| Token | Imzo/muddat |
| Ruxsat | Rol/egalik |
5. Muhandislik saboqlari
- Mijoz — foydalanuvchi nazoratida, ishonsiz
- Frontend tekshiruvi — qulaylik, xavfsizlik emas
- Xavfsizlik serverda (majburiy)
- Har kirgan ma'lumotni tekshir
6. Xulosa
- "Mijozga ishonma" — xavfsizlik asosi
- Frontend — UI qulayligi; server — himoya
- Faqat frontend tekshirgan — API to'g'ridan ochiq
- Ruxsat har doim serverda tekshirilsin
Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.
Xulosa
Bu darsda ruxsatlarni — rol, egalik va ruxsat qatlamlarini o'rgandik.
Eng muhim uch fikr:
Autentifikatsiya va ruxsat — ikki savol. Autentifikatsiya 20.10-bob "kim sen?" ni aniqlaydi (token bilan), ruxsat esa "sen buni qila olasanmi?" ni tekshiradi (rol/egalik bilan). Status kodlar farqli:
401 Unauthorized— kirmagan (token yo'q/yaroqsiz),403 Forbidden— kirgan, lekin ruxsat yo'q (rol yetmaydi). Kirgan har foydalanuvchi hamma narsani qila olmasligi kerak — bu ruxsatning mohiyati.Rol va bog'liqlik fabrikasi. Rol — foydalanuvchi huquq darajasi (admin, muallif, o'quvchi). Rol tekshiruvi bog'liqlik qilinadi (
faqat_admin) — takror yo'qoladi. Turli rollar uchun bog'liqlik fabrikasi (rol_talab("admin", "muallif")) — parametr olib bog'liqlik qaytaruvchi funksiya — bir fabrika, ko'p ruxsat qoidasi.dependencies=[...]natija kerak bo'lmaganda ishlatiladi.Egalik va "mijozga ishonma". Ba'zi amal rolga emas, egalikka bog'liq: o'z resursingni tahrirlay olasan, boshqanikini yo'q (
resurs["egasi"] != user["ism"] and user["rol"] != "admin"— admin istisnosi bilan). Tekshiruv tartibi: 401 (kirgan?) → 404 (bor?) → 403 (ruxsat?). Eng muhimi — ruxsat har doim serverda tekshiriladi: mijoz (frontend) foydalanuvchi nazoratida, uni chetlab o'tish mumkin, shuning uchun frontend tekshiruvi faqat qulaylik, xavfsizlik serverda.
Keyingi darsda xatolarni boshqarish ni o'rganamiz: HTTPExceptionni chuqurroq, maxsus xato klasslari, global xato ishlovchilari (exception handlers) va foydalanuvchiga tushunarli, izchil xato javoblari.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!