Ich arbeite an einer großen Django-App, für deren Zugriff zum größten Teil ein Login erforderlich ist. Dies bedeutet, dass wir in unserer gesamten App Folgendes verteilt haben:
@login_required
def view(...):
Das ist in Ordnung und funktioniert hervorragend , solange wir daran denken, es überall hinzuzufügen ! Leider vergessen wir manchmal, und der Fehler ist oft nicht besonders offensichtlich. Wenn sich der einzige Link zu einer Ansicht auf einer @ login_required-Seite befindet, werden Sie wahrscheinlich nicht bemerken, dass Sie diese Ansicht tatsächlich erreichen können, ohne sich anzumelden. Aber die Bösen bemerken möglicherweise, was ein Problem ist.
Meine Idee war es, das System umzukehren. Anstatt überall @login_required eingeben zu müssen, hätte ich stattdessen etwas wie:
@public
def public_view(...):
Nur für die Öffentlichkeit. Ich habe versucht, dies mit Middleware zu implementieren, und ich konnte es anscheinend nicht zum Laufen bringen. Alles, was ich versucht habe, hat schlecht mit anderer Middleware interagiert, die wir verwenden, denke ich. Als nächstes habe ich versucht, etwas zu schreiben, um die URL-Muster zu durchlaufen, um zu überprüfen, ob alles, was nicht @public ist, als @login_required markiert ist - zumindest dann würden wir einen schnellen Fehler erhalten, wenn wir etwas vergessen. Aber dann konnte ich nicht herausfinden, ob @login_required auf eine Ansicht angewendet wurde ...
Also, was ist der richtige Weg, um dies zu tun? Danke für die Hilfe!
Antworten:
Middleware ist möglicherweise die beste Wahl. Ich habe diesen Code in der Vergangenheit verwendet, modifiziert von einem Snippet, das an anderer Stelle gefunden wurde:
Listen Sie dann in settings.py die Basis-URLs auf, die Sie schützen möchten:
Solange Ihre Site den URL-Konventionen für die Seiten entspricht, für die eine Authentifizierung erforderlich ist, funktioniert dieses Modell. Wenn dies keine Eins-zu-Eins-Anpassung ist, können Sie die Middleware an Ihre Umstände anpassen.
Was mir an diesem Ansatz gefällt - abgesehen davon, dass die Codebasis nicht mehr mit
@login_required
Dekorateuren übersät werden muss - ist, dass Sie einen Ort haben, an dem Sie globale Änderungen vornehmen können, wenn sich das Authentifizierungsschema ändert.quelle
@public
Dekorator zu erstellen, der das_public
Attribut für die Ansicht festlegt , und die Middleware überspringt diese Ansichten dann. Djangos Dekorateur csrf_exempt funktioniert genausoEs gibt eine Alternative zum Dekorieren jeder Ansichtsfunktion. Sie können den
login_required()
Dekorateur auch in dieurls.py
Datei einfügen. Obwohl dies noch eine manuelle Aufgabe ist, haben Sie zumindest alles an einem Ort, was die Prüfung erleichtert.z.B,
Beachten Sie, dass Ansichtsfunktionen direkt benannt und importiert werden, nicht als Zeichenfolgen.
Beachten Sie auch, dass dies mit jedem aufrufbaren Ansichtsobjekt funktioniert, einschließlich Klassen.
quelle
In Django 2.1 können wir alle Methoden in einer Klasse dekorieren mit:
UPDATE: Ich habe auch festgestellt, dass Folgendes funktioniert:
und
LOGIN_URL = '/accounts/login/'
in Ihrer settings.py einstellenquelle
Es ist schwierig, die in Django integrierten Annahmen zu ändern, ohne die Art und Weise zu überarbeiten, wie URLs zum Anzeigen von Funktionen übergeben werden.
Anstatt in Django-Interna herumzuspielen, können Sie hier ein Audit verwenden. Überprüfen Sie einfach jede Ansichtsfunktion.
Führen Sie dies aus und überprüfen Sie die Ausgabe auf
def
s ohne geeignete Dekoratoren.quelle
Hier ist eine Middleware-Lösung für Django 1.10+
Die Middlewares in müssen in Django 1.10+ neu geschrieben werden .
Code
Installation
Zu MIDDLEWARE hinzufügen
MIDDLEWARE = [... '.middleware.RequireLoginMiddleware', # Login erforderlich]
Quellen:
Diese Antwort von Daniel Naab
Django Middleware Tutorial von Max Goodridge
Django Middleware Docs
quelle
__call__
, derprocess_view
Haken immer noch verwendet wird [bearbeitet]Inspiriert von Ber's Antwort schrieb ich einen kleinen Ausschnitt, der die
patterns
Funktion ersetzt, indem ich alle URL-Rückrufe mit demlogin_required
Dekorateur umwickelte . Dies funktioniert in Django 1.6.Die Verwendung funktioniert folgendermaßen (der Aufruf von
list
ist aufgrund der erforderlichyield
).quelle
Das kann man nicht wirklich gewinnen. Sie müssen lediglich eine Erklärung der Autorisierungsanforderungen abgeben. Wo sonst würden Sie diese Deklaration platzieren, außer direkt neben der Ansichtsfunktion?
Ersetzen Sie Ihre Ansichtsfunktionen durch aufrufbare Objekte.
Anschließend machen Sie Ihre Ansichtsfunktionen zu Unterklassen von
LoginViewFunction
.Es werden keine Codezeilen gespeichert. Und es hilft nicht dem Problem "Wir haben vergessen". Sie können lediglich den Code untersuchen, um sicherzustellen, dass die Ansichtsfunktionen Objekte sind. Von der richtigen Klasse.
Aber selbst dann werden Sie nie wirklich wissen, dass jede Ansichtsfunktion ohne eine Unit-Test-Suite korrekt ist.
quelle
def
's greifen . Sie können trivial ein sehr kurzes Skript schreiben, um alledef
in allen Ansichtsmodulen zu scannen und festzustellen, ob ein @login_required vergessen wurde.urls.py
.Es wäre möglich, einen einzigen Ausgangspunkt für alle
urls
in einer Art Include zu haben, der ihn mit diesen Paketen https://github.com/vorujack/decorate_url dekoriert .quelle
Es gibt eine App, die eine Plug-and-Play-Lösung dafür bietet:
https://github.com/mgrouchy/django-stronghold
quelle