DRF Throttling: Verwendung von "scope" – Vergleich von ScopedRateThrottle und UserRateThrottle‑Vererbung

In DRF gibt es zwei häufig genutzte Muster, wenn man scope‑basierte Throttling anwendet.

  • Muster A: Erstellen einer eigenen Klasse, die UserRateThrottle (oder SimpleRateThrottle) erbt und dort einen festen scope definiert. Diese Klasse wird dann direkt in throttle_classes der View eingesetzt.
  • Muster B: Registrieren von ScopedRateThrottle in DEFAULT_THROTTLE_CLASSES und in der View lediglich throttle_scope = "login" angeben.

Frage: "Gibt es letztlich keinen Unterschied?"

Wenn man nur einen einzelnen Ratenlimit‑Wert für "userID (oder nicht‑authentifizierte IP) + scope" festlegen möchte, sind die Resultate nahezu identisch. Der Unterschied liegt jedoch in Anwendungssicherheit, Erweiterbarkeit (mehrere Richtlinien/benutzerdefinierte Kriterien) und Code‑Struktur (Einstellungen vs. Code).


Gemeinsam: Beide erzeugen einen Schlüssel aus "scope + (user ID oder IP)"

  • ScopedRateThrottle baut den Schlüssel aus throttle_scope + userID/IP und sucht den entsprechenden Wert in DEFAULT_THROTTLE_RATES.
  • UserRateThrottle verwendet ebenfalls userID (authentifiziert) bzw. IP (nicht‑authentifiziert). Für mehrere Richtlinien empfiehlt DRF, die Klasse zu erben und unterschiedliche scopes zu setzen.

Unterschied 1) Wo wird der scope definiert? – View‑Attribut vs. Klassen‑Attribut

Muster A: Scope fest in der Klasse (explizit)

from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

class CustomDomainSaveThrottle(UserRateThrottle):
    scope = "custom_domain_save"

class SaveCustomDomainView(APIView):
    throttle_classes = [CustomDomainSaveThrottle]
  • Der scope ist in der Klasse festgelegt.
  • Die View muss lediglich die Klasse referenzieren.
  • Tippfehler im scope‑String werden reduziert – die Klassennamen dienen als Dokumentation.

Muster B: Scope in der View, gemeinsamer Throttle (Einstellungen)

REST_FRAMEWORK = {
  "DEFAULT_THROTTLE_CLASSES": [
    "rest_framework.throttling.ScopedRateThrottle",
  ],
  "DEFAULT_THROTTLE_RATES": {
    "login": "5/min",
  }
}

from rest_framework.views import APIView

class LoginView(APIView):
    throttle_scope = "login"
  • Der scope wird direkt in der View gesetzt.
  • Der gemeinsame Throttle (ScopedRateThrottle) interpretiert den Scope und holt die Rate aus den Einstellungen.
  • Der Code ist kompakter und die Richtlinien lassen sich zentral in den Einstellungen verwalten.

Unterschied 2) Wer garantiert die Anwendung? – Globale Registrierung vs. View‑spezifische Montage

Punkt B (häufig missverstanden)

Selbst wenn ScopedRateThrottle in DEFAULT_THROTTLE_CLASSES registriert ist, wird er nicht auf Views ohne throttle_scope angewendet.

Vorteil von Muster A

Man kann ohne globale Einstellungen gezielt bestimmte Views mit einem gewünschten Throttle ausstatten. Das ist praktisch, wenn die globalen Einstellungen nicht geändert werden dürfen oder nur ein Teil der API streng limitiert werden soll.


Unterschied 3) Erweiterbarkeit: Mehr als ein einzelnes Limit – Muster A gewinnt

Die beiden Muster sehen ähnlich aus, solange es nur ein Scope und ein Limit pro View gibt. Sobald man jedoch mehr als ein Limit benötigt, unterscheiden sie sich deutlich.

1) Mehrere Throttles (z. B. Burst + Sustained)

DRF‑Dokumentation zeigt ein Beispiel, bei dem mehrere UserRateThrottle‑Klassen gleichzeitig verwendet werden.

class Burst(UserRateThrottle):
    scope = "burst"

class Sustained(UserRateThrottle):
    scope = "sustained"

class SearchView(APIView):
    throttle_classes = [Burst, Sustained]

Mit ScopedRateThrottle lässt sich nicht einfach zwei unterschiedliche scopes für dieselbe View definieren – man braucht wieder eigene Klassen (oder eine eigene Implementierung).

2) Andere Kriterien als userID/IP

ScopedRateThrottle arbeitet standardmäßig mit userID bzw. IP. In der Praxis tauchen jedoch häufig andere Anforderungen auf:

  • Login: Limitierung nach IP + Benutzername (z. B. für Account‑Target‑Angriffe).
  • Organisation/Teenant: Limitierung nach tenant_id.
  • API‑Key: Limitierung pro Schlüssel.

Diese Szenarien erfordern eine Anpassung von get_cache_key() und führen daher zu einer benutzerdefinierten Throttle‑Klasse – also zu Muster A.


Zwei Schlüssel, die eine API‑Verbindung öffnen

Was sollte man wählen?

Für die meisten "View‑spezifischen Rate‑Limits" → Muster B (ScopedRateThrottle)

  • Minimaler Code
  • Zentrale Verwaltung in den Einstellungen
  • Nur Views mit throttle_scope werden limitiert

Wenn eines der folgenden zutrifft → Muster A (Vererbung/benutzerdefinierte Klasse)

  • Mehrere Limits (z. B. Burst + Sustained) gleichzeitig auf einer View
  • Nicht‑userID/IP‑Kriterien (z. B. IP + Username, tenant, API‑Key)
  • Globale Einstellungen sollen nicht verändert werden, aber bestimmte Views müssen limitiert werden
  • Die Klassennamen sollen als Dokumentation dienen

Weiterführender Artikel: