IlmHamroh
Python kursi/Django14/16-dars16 daqiqa
Mundarija (22)

21.14-dars: Ruxsat va throttling

21-QISM — DJANGO · 14-dars


1. Kirish va motivatsiya

API tayyor (view, serializer), lekin u himoyasiz: har kim har amalni qila oladi, va cheksiz so'rov yubora oladi (server yuki). Bu darsda DRF'ning himoya vositalarini o'rganamiz: ruxsat (permission — kim nima qila oladi) va throttling (so'rov sonini cheklash — rate limiting).

Bu 20.11 dagi ruxsatlar va 20-qismdagi xavfsizlikning DRF versiyasi — lekin tayyor klasslar bilan. IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly — ruxsat klasslari; AnonRateThrottle, UserRateThrottle — so'rov cheklovchilari. Bir necha qator bilan API himoyalanadi.

Real vaziyat. Bir API ochiq edi — har kim ma'lumot o'chira olardi (ruxsatsiz), va bir bot minutiga minglab so'rov yuborib serverni yiqitdi (DoS). Jamoa DRF himoyasini qo'shdi: IsAuthenticated (faqat kirganlar), IsAdminUser (o'chirish — admin), UserRateThrottle (soatiga 100 so'rov). Endi API himoyalangan va cheklangan. DRF ruxsat/throttling — API xavfsizligining tayyor qatlami.

Bu darsda ruxsat va throttlingni — permission klasslari va rate limitingni o'rganamiz.

Bu darsda:

  • Ruxsat klasslari (IsAuthenticated, ...)
  • permission_classes
  • IsAuthenticatedOrReadOnly (o'qish ochiq)
  • Maxsus ruxsat (obyekt darajasida)
  • Throttling (so'rov cheklash)
  • AnonRateThrottle/UserRateThrottle
  • 429 Too Many Requests
  • Amaliy: himoyalangan API

ℹ Misollarda DRF APIClient bilan sinaladi.


2. Nazariya — chuqur tushuntirish

2.1. Ruxsat klasslari

DRF tayyor ruxsat klasslari beradi:

Klass Ruxsat
AllowAny Hamma (ochiq)
IsAuthenticated Faqat kirganlar
IsAdminUser Faqat admin (is_staff)
IsAuthenticatedOrReadOnly O'qish — hamma, yozish — kirganlar

Ruxsat klasslari — kim view'ga kira olishini belgilaydi 20.11-bob. IsAuthenticated — kirmagan → 403; IsAdminUser — admin bo'lmagan → 403. Bu 20.11 dagi rol/ruxsat tekshiruvining tayyor versiyasi.

2.2. permission_classes

View'ga ruxsat qo'shish:

python
from rest_framework.permissions import IsAuthenticated
from rest_framework.decorators import api_view, permission_classes

@api_view(["GET"])
@permission_classes([IsAuthenticated])
def profil(request):
    return Response({"ism": request.user.username})

# klassli:
class KursView(APIView):
    permission_classes = [IsAuthenticated]

permission_classes — view uchun ruxsat klasslari ro'yxati. Funksiyali view'da @permission_classes([...]), klassli view'da permission_classes = [...]. Barcha klasslar o'tishi kerak (VA). Ruxsatsiz → 403.

2.3. IsAuthenticatedOrReadOnly

Ko'p tarqalgan naqsh — o'qish ochiq, yozish himoyalangan:

python
from rest_framework.permissions import IsAuthenticatedOrReadOnly

class KursViewSet(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticatedOrReadOnly]
    # GET (o'qish) — hamma; POST/PUT/DELETE (yozish) — kirganlar

IsAuthenticatedOrReadOnly — xavfsiz metodlar (GET, HEAD — o'qish, 20.2) hamma uchun; o'zgartiruvchi metodlar (POST, PUT, DELETE — yozish) faqat kirganlar. Bu keng tarqalgan: ma'lumotni hamma ko'radi, faqat kirganlar o'zgartiradi.

2.4. Maxsus ruxsat (obyekt darajasida)

O'z ruxsat klasslaringiz (egalik, 20.11):

python
from rest_framework.permissions import BasePermission, SAFE_METHODS

class FaqatEgasi(BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in SAFE_METHODS:
            return True                  # o'qish — hamma
        return obj.muallif == request.user   # yozish — egasi

Maxsus ruxsat — BasePermissiondan meros: has_permission (umumiy), has_object_permission (obyekt darajasida — egalik). Bu 20.11 dagi egalik tekshiruvining DRF versiyasi. SAFE_METHODS — o'qish metodlari.

2.5. Throttling (so'rov cheklash)

Throttling — so'rov sonini cheklaydi (rate limiting):

python
# settings.py:
REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_RATES": {
        "anon": "100/hour",       # anonim
        "user": "1000/hour",      # kirgan
    },
}

Throttling — bir foydalanuvchi/IP chekli so'rov yubora oladi (masalan, soatiga 100). Ortiqcha so'rov → 429 Too Many Requests. Bu serverni himoya qiladi (DoS, suiiste'mol) va adolat (bir kishi hammasini band qilmasin).

2.6. AnonRateThrottle / UserRateThrottle

Ikki asosiy throttle:

Throttle Kim uchun Kalit
AnonRateThrottle Anonim (kirmagan) IP manzil
UserRateThrottle Kirgan Foydalanuvchi ID
ScopedRateThrottle Endpoint bo'yicha Maxsus
python
from rest_framework.throttling import UserRateThrottle

class KursView(APIView):
    throttle_classes = [UserRateThrottle]

AnonRateThrottle — anonim so'rovlarni IP bo'yicha cheklaydi; UserRateThrottle — kirgan foydalanuvchini ID bo'yicha. Ikkalasi birga (anonim kam, kirgan ko'p). ScopedRateThrottle — muayyan endpoint uchun (masalan, login — kam).

2.7. 429 Too Many Requests

Throttle chegarasi oshsa — 429:

so'rov 1-100: 200 OK
so'rov 101:   429 Too Many Requests (Retry-After: ...)

429 Too Many Requests — throttle chegarasi oshdi. Retry-After sarlavhasi — qachon qayta urinish mumkin. Mijoz buni ko'rib kutadi. Bu 20.6 dagi status kodlarning biri (server himoyasi).

2.8. API himoya qatlamlari

DRF himoya — bir necha qatlam:

Qatlam Vazifa
Autentifikatsiya Kim (token/sessiya)
Ruxsat Nima qila oladi
Throttling Qancha so'rov
Validatsiya Ma'lumot to'g'rimi (serializer)

DRF API himoyasi qatlam-qatlam (20.11, 20.12): autentifikatsiya (kim), ruxsat (nima), throttling (qancha), validatsiya (ma'lumot). Har qatlam bir himoya. Bular birga — xavfsiz, mustahkam API. Hammasi tayyor klasslar bilan.


3. Tez ma'lumotnoma

python
from rest_framework.permissions import IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly, BasePermission, SAFE_METHODS
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
from rest_framework.decorators import api_view, permission_classes, throttle_classes

# ruxsat:
@api_view(["GET"])
@permission_classes([IsAuthenticated])
def profil(request): ...

class KursViewSet(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticatedOrReadOnly]
    throttle_classes = [UserRateThrottle]

# maxsus ruxsat:
class FaqatEgasi(BasePermission):
    def has_object_permission(self, request, view, obj):
        return request.method in SAFE_METHODS or obj.muallif == request.user

# settings.py:
REST_FRAMEWORK = {"DEFAULT_THROTTLE_RATES": {"anon": "100/hour", "user": "1000/hour"}}

Ruxsat/throttle

AllowAny · IsAuthenticated · IsAdminUser · IsAuthenticatedOrReadOnly
AnonRateThrottle · UserRateThrottle · 429 Too Many Requests

4. Batafsil misollar

Misollarda DRF APIClient bilan sinaladi.

Misol 1 — Ruxsat klasslari

python
"""ruxsat klasslari (AllowAny, IsAuthenticated); permission_classes; kirmagan → 403; kirgan → 200."""

import warnings
warnings.filterwarnings("ignore")

import sys
import tempfile
import types
from io import StringIO

import django
from django.conf import settings

settings.configure(
    DEBUG=False,
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["django.contrib.contenttypes", "django.contrib.auth", "django.contrib.sessions", "rest_framework", "wisar"],
    ROOT_URLCONF=__name__,
    ALLOWED_HOSTS=["*"],
    SECRET_KEY="namuna",
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()

from django.core.management import call_command

call_command("migrate", stdout=StringIO(), verbosity=0)

from django.contrib.auth.models import User
from django.urls import path
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response


@api_view(["GET"])
@permission_classes([AllowAny])
def ochiq(request):
    return Response({"xabar": "hamma uchun"})


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def himoyalangan(request):
    return Response({"ism": request.user.username})


urlpatterns = [path("ochiq/", ochiq), path("profil/", himoyalangan)]


def main() -> None:
    from rest_framework.test import APIClient
    client = APIClient()

    print("=== 1. Ochiq endpoint (AllowAny) ===")
    print(f"  /ochiq/ → status {client.get('/ochiq/').status_code}")

    print("\n=== 2. ⚠️ Himoyalangan (kirmagan → 403) ===")
    print(f"  /profil/ (kirmagan) → status {client.get('/profil/').status_code}")

    print("\n=== 3. Himoyalangan (kirgach → 200) ===")
    ali = User.objects.create_user(username="ali", password="p")
    client.force_authenticate(user=ali)
    javob = client.get("/profil/")
    print(f"  /profil/ (kirgan) → status {javob.status_code}, {javob.json()}")

    print("\n=== 4. Chiqgach yana himoyalangan ===")
    client.force_authenticate(user=None)
    print(f"  /profil/ (chiqgach) → status {client.get('/profil/').status_code}")
    print("  ⭐ permission_classes — IsAuthenticated (kirmagan → 403)")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ochiq endpoint (AllowAny) ===
  /ochiq/ → status 200

=== 2. ⚠️ Himoyalangan (kirmagan → 403) ===
  /profil/ (kirmagan) → status 403

=== 3. Himoyalangan (kirgach → 200) ===
  /profil/ (kirgan) → status 200, {'ism': 'ali'}

=== 4. Chiqgach yana himoyalangan ===
  /profil/ (chiqgach) → status 403
  ⭐ permission_classes — IsAuthenticated (kirmagan → 403)

Nima ko'rsatdi: 2.1, 2.2-bo'limlar.

Misol 2 — IsAuthenticatedOrReadOnly va admin

python
"""IsAuthenticatedOrReadOnly (o'qish ochiq, yozish himoyalangan); IsAdminUser; xavfsiz vs o'zgartiruvchi metod."""

import warnings
warnings.filterwarnings("ignore")

import sys
import tempfile
import types
from io import StringIO

import django
from django.conf import settings

settings.configure(
    DEBUG=False,
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["django.contrib.contenttypes", "django.contrib.auth", "django.contrib.sessions", "rest_framework", "wisar"],
    ROOT_URLCONF=__name__,
    ALLOWED_HOSTS=["*"],
    SECRET_KEY="namuna",
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()

from django.core.management import call_command

call_command("migrate", stdout=StringIO(), verbosity=0)

from django.contrib.auth.models import User
from django.db import connection, models
from django.urls import include, path
from rest_framework import routers, serializers, viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly


class Kurs(models.Model):
    nom = models.CharField(max_length=100)

    class Meta:
        app_label = "wisar"


class KursSerializer(serializers.ModelSerializer):
    class Meta:
        model = Kurs
        fields = ["id", "nom"]


class KursViewSet(viewsets.ModelViewSet):
    queryset = Kurs.objects.all()
    serializer_class = KursSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]


router = routers.SimpleRouter()
router.register("kurslar", KursViewSet)
urlpatterns = [path("api/", include(router.urls))]


def main() -> None:
    with connection.schema_editor() as se:
        se.create_model(Kurs)
    Kurs.objects.create(nom="Python")

    from rest_framework.test import APIClient
    client = APIClient()

    print("=== 1. O'qish ochiq (kirmagan, GET) ===")
    print(f"  GET /api/kurslar/ → status {client.get('/api/kurslar/').status_code}")

    print("\n=== 2. ⚠️ Yozish himoyalangan (kirmagan, POST) ===")
    javob = client.post("/api/kurslar/", {"nom": "Go"}, format="json")
    print(f"  POST (kirmagan) → status {javob.status_code}")

    print("\n=== 3. Yozish (kirgach, POST) ===")
    ali = User.objects.create_user(username="ali", password="p")
    client.force_authenticate(user=ali)
    javob = client.post("/api/kurslar/", {"nom": "Go"}, format="json")
    print(f"  POST (kirgan) → status {javob.status_code}")

    print("\n=== 4. O'qish har doim ochiq ===")
    client.force_authenticate(user=None)
    print(f"  GET (chiqgach) → status {client.get('/api/kurslar/').status_code}")
    print("  ⭐ IsAuthenticatedOrReadOnly — o'qish hamma, yozish kirganlar")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. O'qish ochiq (kirmagan, GET) ===
  GET /api/kurslar/ → status 200

=== 2. ⚠️ Yozish himoyalangan (kirmagan, POST) ===
  POST (kirmagan) → status 403

=== 3. Yozish (kirgach, POST) ===
  POST (kirgan) → status 201

=== 4. O'qish har doim ochiq ===
  GET (chiqgach) → status 200
  ⭐ IsAuthenticatedOrReadOnly — o'qish hamma, yozish kirganlar

Nima ko'rsatdi: 2.3-bo'lim.

Misol 3 — Throttling (so'rov cheklash)

python
"""throttling (so'rov cheklash); AnonRateThrottle; 2/min rate; 429 Too Many Requests; server himoyasi."""

import warnings
warnings.filterwarnings("ignore")

import sys
import tempfile
import types
from io import StringIO

import django
from django.conf import settings

settings.configure(
    DEBUG=False,
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["django.contrib.contenttypes", "django.contrib.auth", "django.contrib.sessions", "rest_framework", "wisar"],
    ROOT_URLCONF=__name__,
    ALLOWED_HOSTS=["*"],
    SECRET_KEY="namuna",
    REST_FRAMEWORK={"DEFAULT_THROTTLE_RATES": {"anon": "3/min"}},
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()

from django.core.management import call_command

call_command("migrate", stdout=StringIO(), verbosity=0)

from django.urls import path
from rest_framework.response import Response
from rest_framework.throttling import AnonRateThrottle
from rest_framework.views import APIView


class CheklanganView(APIView):
    throttle_classes = [AnonRateThrottle]

    def get(self, request):
        return Response({"ok": True})


urlpatterns = [path("cheklangan/", CheklanganView.as_view())]


def main() -> None:
    from rest_framework.test import APIClient
    client = APIClient()

    print("=== 1. Rate cheklovi: 3/min ===")
    print("  har anonim IP minutiga 3 so'rov")

    print("\n=== 2. So'rovlar (4 marta) ===")
    kodlar = [client.get("/cheklangan/").status_code for _ in range(5)]
    print(f"  status kodlar: {kodlar}")

    print("\n=== 3. Chegaradan keyin 429 ===")
    print(f"  1-3 so'rov: 200 (ruxsat), 4+: 429 (Too Many Requests)")

    print("\n=== 4. Server himoyasi ===")
    print(f"  429 soni: {kodlar.count(429)} (chegaradan oshgan)")
    print("  ⭐ throttling — so'rov cheklash; 429 (DoS/suiiste'mol himoyasi)")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Rate cheklovi: 3/min ===
  har anonim IP minutiga 3 so'rov

=== 2. So'rovlar (4 marta) ===
  status kodlar: [200, 200, 200, 429, 429]

=== 3. Chegaradan keyin 429 ===
  1-3 so'rov: 200 (ruxsat), 4+: 429 (Too Many Requests)

=== 4. Server himoyasi ===
  429 soni: 2 (chegaradan oshgan)
  ⭐ throttling — so'rov cheklash; 429 (DoS/suiiste'mol himoyasi)

Nima ko'rsatdi: 2.5, 2.6, 2.7-bo'limlar.

Misol 4 — Amaliy: himoyalangan API (ruxsat + throttle)

Ruxsat va throttlingni birlashtirgan to'liq himoyalangan API: o'qish ochiq, yozish kirganlarga, va so'rov cheklovi. Bu — real DRF API'ning himoya qatlami.

python
"""to'liq himoya: IsAuthenticatedOrReadOnly + throttling; o'qish ochiq, yozish himoyalangan, cheklangan; qatlamli."""

import warnings
warnings.filterwarnings("ignore")

import sys
import tempfile
import types
from io import StringIO

import django
from django.conf import settings

settings.configure(
    DEBUG=False,
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["django.contrib.contenttypes", "django.contrib.auth", "django.contrib.sessions", "rest_framework", "wisar"],
    ROOT_URLCONF=__name__,
    ALLOWED_HOSTS=["*"],
    SECRET_KEY="namuna",
    REST_FRAMEWORK={"DEFAULT_THROTTLE_RATES": {"user": "100/min", "anon": "50/min"}},
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()

from django.core.management import call_command

call_command("migrate", stdout=StringIO(), verbosity=0)

from django.contrib.auth.models import User
from django.db import connection, models
from django.urls import include, path
from rest_framework import routers, serializers, viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle


class Kurs(models.Model):
    nom = models.CharField(max_length=100)

    class Meta:
        app_label = "wisar"


class KursSerializer(serializers.ModelSerializer):
    class Meta:
        model = Kurs
        fields = ["id", "nom"]


class KursViewSet(viewsets.ModelViewSet):
    queryset = Kurs.objects.all()
    serializer_class = KursSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]
    throttle_classes = [AnonRateThrottle, UserRateThrottle]


router = routers.SimpleRouter()
router.register("kurslar", KursViewSet)
urlpatterns = [path("api/", include(router.urls))]


def main() -> None:
    with connection.schema_editor() as se:
        se.create_model(Kurs)
    Kurs.objects.create(nom="Python")

    from rest_framework.test import APIClient
    client = APIClient()

    print("=== 1. O'qish (anonim, ochiq) ===")
    print(f"  GET → status {client.get('/api/kurslar/').status_code}")

    print("\n=== 2. ⚠️ Yozish (anonim, taqiq) ===")
    print(f"  POST (anonim) → status {client.post('/api/kurslar/', {'nom': 'Go'}, format='json').status_code}")

    print("\n=== 3. Yozish (kirgan, ruxsat) ===")
    ali = User.objects.create_user(username="ali", password="p")
    client.force_authenticate(user=ali)
    print(f"  POST (kirgan) → status {client.post('/api/kurslar/', {'nom': 'Go'}, format='json').status_code}")

    print("\n=== 4. Himoya qatlamlari ===")
    print("  autentifikatsiya (kim) → ruxsat (nima) → throttle (qancha)")
    print(f"  jami kurslar: {Kurs.objects.count()}")
    print("  ⭐ ruxsat + throttle — qatlamli API himoyasi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. O'qish (anonim, ochiq) ===
  GET → status 200

=== 2. ⚠️ Yozish (anonim, taqiq) ===
  POST (anonim) → status 403

=== 3. Yozish (kirgan, ruxsat) ===
  POST (kirgan) → status 201

=== 4. Himoya qatlamlari ===
  autentifikatsiya (kim) → ruxsat (nima) → throttle (qancha)
  jami kurslar: 2
  ⭐ ruxsat + throttle — qatlamli API himoyasi

Nima ko'rsatdi: 2.1–2.8-bo'limlar.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"API himoyasiz bo'lsin" Ruxsat + throttle
"Ruxsatni qo'lda yozish" Tayyor klasslar
"Barcha yoki hech" IsAuthenticatedOrReadOnly
"So'rov cheksiz" Throttling (rate limit)
"Egalik qo'lda har view'da" Maxsus permission klass
"429 — xato" Throttle (normal himoya)
"Anonim va kirgan bir xil limit" Alohida (anon/user)
"Ruxsat = autentifikatsiya" Kim (auth) vs nima (perm)

6. Keng tarqalgan xatolar va yechimlari

1. API'ni himoyasiz qoldirish

python
class KursViewSet(viewsets.ModelViewSet): ...   # ⚠️ hamma o'chira oladi
permission_classes = [IsAuthenticatedOrReadOnly]   # ✅

2. Ruxsatni qo'lda tekshiruv

python
def get(self, request):
    if not request.user.is_authenticated: ...    # ⚠️ har view'da
permission_classes = [IsAuthenticated]           # ✅

3. Throttlingsiz (DoS xavfi)

python
# throttle yo'q                                  # ⚠️ cheksiz so'rov
throttle_classes = [UserRateThrottle]            # ✅

4. Anonim va kirganga bir xil limit

python
"anon": "1000/hour"                              # ⚠️ anonim ko'p
"anon": "100/hour", "user": "1000/hour"          # ✅

5. Egalikni umumiy ruxsatda

python
# has_permission'da egalik                        # ⚠️ obyekt yo'q
def has_object_permission(self, ...): ...        # ✅ obyekt darajasida

6. SAFE_METHODSni unutish (maxsus ruxsatda)

python
return obj.muallif == request.user               # ⚠️ o'qish ham taqiq
if request.method in SAFE_METHODS: return True   # ✅ o'qish ochiq

7. 429ni xato deb qabul qilish

python
# 429 → xato deb log                              # ⚠️ normal himoya
# 429 → Retry-After kutish (mijoz)                # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 20.11-dars (o'tilgan): ruxsatlar — DRF versiyasi
  • 21.11-dars (o'tilgan): auth — ruxsat asosi
  • 21.12/21.13-dars (o'tilgan): DRF, serializer
  • 20.6-dars (o'tilgan): status kodlar — 403, 429
  • 28-qism: infratuzilma — rate limiting (server darajasida)

8. Eng yaxshi amaliyotlar

  1. API'ni ruxsat klasslari bilan himoyalang.

  2. Tayyor ruxsat klasslarini ishlating (IsAuthenticated).

  3. IsAuthenticatedOrReadOnly — o'qish ochiq, yozish himoyalangan.

  4. Egalik uchun maxsus permission (has_object_permission).

  5. Throttling bilan so'rov sonini cheklang (DoS himoyasi).

  6. Anonim va kirganga alohida limit.

  7. SAFE_METHODS bilan o'qishni ochiq qoldiring.

  8. 429ni normal himoya deb qabul qiling (Retry-After).


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # ruxsat klassi nima?
2.  # IsAuthenticated nima?
3.  # permission_classes nima?
4.  # IsAuthenticatedOrReadOnly nima?
5.  # has_object_permission nima?
6.  # throttling nima?
7.  # AnonRateThrottle nima?
8.  # UserRateThrottle nima?
9.  # 429 nima?
10. # SAFE_METHODS nima?
11. # ruxsat va auth farqi?
12. # ruxsatsiz status?
Javoblar
  1. Kim view'ga kira olishini belgilaydi
  2. Faqat kirganlar
  3. View ruxsat klasslari ro'yxati
  4. O'qish — hamma, yozish — kirganlar
  5. Obyekt darajasidagi ruxsat (egalik)
  6. So'rov sonini cheklash (rate limit)
  7. Anonim so'rovni IP bo'yicha cheklaydi
  8. Kirgan foydalanuvchini ID bo'yicha
  9. Too Many Requests (throttle oshdi)
  10. O'qish metodlari (GET, HEAD)
  11. Auth — kim; ruxsat — nima qila oladi
  12. 403 (Forbidden)

Vazifa 2: Xatolarni tuzating

python
1.  class KursViewSet(viewsets.ModelViewSet): ...   # himoya

2.  if not request.user.is_authenticated: ...       # permission

3.  # throttle yo'q                                  # DoS

4.  "anon": "1000/hour"                              # limit

5.  return obj.muallif == request.user               # SAFE
Javoblar
python
1.  permission_classes = [IsAuthenticatedOrReadOnly]

2.  permission_classes = [IsAuthenticated]

3.  throttle_classes = [UserRateThrottle]

4.  "anon": "100/hour", "user": "1000/hour"

5.  if request.method in SAFE_METHODS: return True
    return obj.muallif == request.user

Vazifa 3: Himoyalangan API

Ruxsat bilan API:

  1. IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly
  2. Har biri uchun endpoint
  3. Kirgan/kirmagan test
  4. 403 holatlari

Vazifa 4: Maxsus ruxsat

Egalik ruxsati:

  1. FaqatEgasi permission klass
  2. has_object_permission
  3. SAFE_METHODS (o'qish ochiq)
  4. Ega/begona test

Vazifa 5: Throttling

So'rov cheklash:

  1. AnonRateThrottle, UserRateThrottle
  2. Turli rate (anon/user)
  3. 429 holati
  4. Chegara test

Vazifa 6: To'liq himoya

Qatlamli API:

  1. Auth + ruxsat + throttle
  2. O'qish/yozish farqi
  3. Anonim/kirgan/admin
  4. Har qatlam test

Vazifa 7: O'ylash

DRF ruxsat va throttling — API himoyasini qatlamlarga ajratadi: autentifikatsiya (kim), ruxsat (nima qila oladi), throttling (qancha). Har qatlam bir himoya, va birga ular mustahkam. Bu "chuqurlikda himoya" (defense in depth) tamoyili — bir himoya buzilsa, boshqasi ushlaydi. Xavfsizlikni ko'p qatlamga taqsimlashning afzalligi nima, va nima uchun bitta himoyaga tayanish (masalan, faqat auth) xatarli?

Javob

Qisqa javob: DRF himoya qatlamlarga ajratilgan: auth (kim), ruxsat (nima), throttle (qancha), validatsiya (ma'lumot). Har qatlam bir vazifaga mas'ul, va birga ular mustahkam. "Chuqurlikda himoya" — bir qatlam yetmasa/buzilsa, boshqasi ushlaydi. Ko'p qatlamga taqsimlashning afzalligi: bir nuqta buzilish butun tizimni buzmaydi (auth o'tib ketsa, ruxsat ushlaydi; ruxsat o'tsa, throttle serverni himoya qiladi). Bitta himoyaga tayanish xatarli, chunki u bitta buzilish nuqtasi — u buzilsa, hech nima qolmaydi. Ko'p qatlam — ishonchli (bir xato halokatli emas).

1. Qatlamlar

Qatlam Vazifa
Autentifikatsiya Kim (token/sessiya)
Ruxsat Nima qila oladi
Throttling Qancha so'rov
Validatsiya Ma'lumot to'g'rimi

2. Chuqurlikda himoya

Bir qatlam buzilsa/yetmasa — boshqasi ushlaydi. Himoya takrorlangan (har qatlam mustaqil).

3. Bitta himoya xatarli

Faqat auth bo'lsa — u buzilsa (token o'g'irlansa), hamma narsa ochiq. Bitta buzilish nuqtasi — halokatli. Ko'p qatlam — bir buzilish butun tizimni buzmaydi.

4. "Chuqurlikda himoya" boshqa joyda

Soha Qatlamlar
DRF Auth/ruxsat/throttle
Tarmoq Firewall/VPN/shifrlash
Kirish Parol/2FA/qurilma
Ma'lumot Validatsiya/escape/parametr

5. Muhandislik saboqlari

  1. Himoyani qatlamlarga taqsimla
  2. Bir qatlam buzilsa — boshqasi ushlaydi
  3. Bitta himoya — bitta buzilish nuqtasi (xatarli)
  4. Chuqurlikda himoya — ishonchli

6. Xulosa

  1. DRF himoya — qatlamli (auth/ruxsat/throttle)
  2. Chuqurlikda himoya — takror, mustaqil
  3. Bitta himoya — halokatli (bir buzilish)
  4. Ko'p qatlam — bir xato halokatli emas

Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.


Xulosa

Bu darsda DRF ruxsat va throttlingni o'rgandik.

Eng muhim uch fikr:

  1. Ruxsat klasslari. DRF tayyor ruxsat klasslari beradi: AllowAny (hamma), IsAuthenticated (kirganlar), IsAdminUser (admin), IsAuthenticatedOrReadOnly (o'qish — hamma, yozish — kirganlar). permission_classes bilan view'ga qo'shiladi (funksiyali — @permission_classes([...]), klassli — permission_classes = [...]). Ruxsatsiz → 403. Bu 20.11 dagi rol/ruxsat tekshiruvining tayyor versiyasi. Egalik uchun maxsus permission (BasePermission, has_object_permission, SAFE_METHODS).

  2. Throttling. Throttling — so'rov sonini cheklaydi (rate limiting): AnonRateThrottle (anonim, IP bo'yicha), UserRateThrottle (kirgan, ID bo'yicha), ScopedRateThrottle (endpoint). DEFAULT_THROTTLE_RATES bilan sozlanadi ("anon": "100/hour"). Chegara oshsa → 429 Too Many Requests (Retry-After bilan). Bu serverni DoS/suiiste'moldan himoya qiladi va adolat ta'minlaydi (bir kishi hammasini band qilmasin).

  3. Qatlamli himoya. DRF API himoyasi qatlam-qatlam: autentifikatsiya (kim), ruxsat (nima qila oladi), throttling (qancha so'rov), validatsiya (ma'lumot to'g'rimi — serializer). Har qatlam bir himoya, va birga ular mustahkam — bu "chuqurlikda himoya" (defense in depth): bir qatlam buzilsa/yetmasa, boshqasi ushlaydi. Bitta himoyaga tayanish xatarli (bitta buzilish nuqtasi); ko'p qatlam — bir xato halokatli emas. Hammasi tayyor DRF klasslari bilan.

Keyingi darsda signal va middleware ni o'rganamiz: Django'ning hodisa tizimi (signals — model saqlanganda avtomatik amal) va middleware (har so'rov/javobni qayta ishlovchi qatlam).

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
21.14-dars: Ruxsat va throttling — IlmHamroh