2015-08-18 3 views
5

Ich entwerfe die Autorisierung einer DRF-Anwendung. Ich brauche Rollen, nicht nur Berechtigungen.Design Django Rest Framework rollenbasierte Autorisierung

Ich habe ein Modell (z. B. project), in dem ich einige Informationen (z. B. Name, Beschreibung), die durch einige Rollen (z. B. admin) geändert werden können. Aber zur gleichen Zeit gibt es andere Rollen (z. B. worker), die nicht in der Lage sein sollten, diese Information innerhalb dieses Modells zu modifizieren, aber dennoch einige andere Informationen (z. B. Anfangs- und Endtermine) modifizieren können.

Ich habe zwei Lösungen für dieses Problem gedacht. Die erste liest die gesendete HTTP-Anfrage und definiert die auszuführenden Aktionen abhängig von der Anfrage. Dies bedeutet, dass jedes Mal, wenn dem Modell ein neues Feld hinzugefügt wird, diese Logik geändert werden muss. Das klingt furchtbar schwer zu pflegen, ist fehleranfällig und kann Schwachstellen verursachen.

Auf der anderen Seite habe ich gedacht, dass ich das Modell in zwei verschiedene Modelle teilen könnte. Einer davon enthält die Daten, die nur eine Rolle (admin) ändern kann, und der andere definiert die anderen Daten, die von beiden Rollen geändert werden können (admin, worker). Auf diese Weise muss ich die HTTP-Anfrage nicht analysieren, denn wenn ich eine POST/PUT-Anfrage bekomme, die das erste Modell betrifft und der Benutzer eine Worker-Rolle hat, kann ich sie direkt ablehnen.

Diese Situation tritt bei mehreren Modellen auf.

Ich würde gerne wissen, ob es einen Standardweg gibt oder ob ich das Rad neu erfinde. Ich denke, dass diese Situation wirklich üblich sein muss. Ich denke zum Beispiel an ein Git-Projekt, bei dem einige Benutzer Zugriff auf eine Sache in einem Projekt haben, aber nicht auf andere.

Ergänzende Hinweise (Feed-back wird sehr geschätzt werden):

  • ich am meisten wahrscheinlich verwenden, um die django-role-permissions Modul Rollen und Berechtigungen zu implementieren. Ich kann keine integrierten django-Gruppen verwenden, da ich ihnen zwar Berechtigungen hinzufügen kann, sie aber zum Gruppieren von Benutzern verwende (ohne mit Rollen zu tun zu haben).

  • Ich werde eine Beziehung zwischen Rollen und Berechtigungen (string-basierte Berechtigung, wie create_project, modify_project_description) in einer Datei mit Berechtigungen erstellen.

  • Wenn ich jede Anfrage erhalte, überprüfe ich, welche Rollen Privilegien haben, um diese Aktion durchzuführen und zu prüfen, ob der Benutzer eine dieser Rollen ist (aktivitätsbasierte Autorisierung, was bedeutet, dass ich am Endpunkt die Aktivität/Aktion überprüfe) der Rolle).

Antwort

1

Nach einigem Nachdenken fand ich zwei Lösungen.

Die erste Lösung war (statt die Modelle zu teilen, wie ich in der Frage erwähnte), unterschiedliche Endpunkte (URLs) für jede Art von Aktion zu deklarieren, die passieren muss. Dann in jedem Endpunkt serializer definieren die gültigen Parameter über die Klassenvariable fields.

Das bedeutet, wenn eine Rolle nur bestimmte Felder aktualisieren kann, würde ich für diese Aktion eine ModelViewSet erstellen und in der serializer Klasse zu diesem ModelViewSet nur bestimmte Parameter zulassen.

Diese Lösung hat viele Probleme und ist nicht ganz RESTful. Sie könnten Dutzende verschiedener URLs erhalten. In meinem Fall, da die API nicht groß ist und die Aktionen begrenzt waren, war das kurzfristig kein Problem, aber sicher, dass es ein Problem gewesen wäre, wenn sich die Anforderungen der Anwendung geändert hätten.

Die zweite (und ausgewählt) Lösung war eine Erlaubnis/Rollen-Tabelle zu definieren, in dem Sie den Endpunkt definieren, wo die Aktion geschehen muss (wenn Sie Ihre Anwendung in der richtigen Art und Weise aufgebaut haben es nur die ModelViewSet sein kann Klassenname), die auszuführende Aktion (list, retrieve, create ...) die Felder des zugehörigen Modells, mit denen interagiert werden kann, und die Rolle, die mit diesen Feldern interagieren kann.

Ich würde vorschlagen, Wörterbücher als die verwendete Datenstruktur für die Berechtigungstabelle zu verwenden, so dass jede Berechtigungsprüfung O(1) ist.

Jedes Mal, wenn Sie eine Anforderung an diesen Endpunkt erhalten, sollte eine Berechtigungsprüfung mit dieser Tabelle durchgeführt werden.

Ich implementierte die Berechtigungsprüfung durch Überschreiben der check_permissions() Methode in der Klasse ModelSetView. Seien Sie vorsichtig und behalten Sie die ursprüngliche check_permissions() Funktionalität dort auch.

2

Klingt, als ob Sie eine Sicherheit auf Feldebene wünschen. Sie könnten prüfen, ob Sie mithilfe von Proxy-Modellen Schreibzugriff auf eine begrenzte Anzahl von Feldern für die eingeschränkten Benutzer erhalten.

Eine andere Option könnte die Verwendung einer benutzerdefinierten Serialisierungsklasse sein, die schreibgeschützt auf einige Felder angewendet wird. get_serializer auf einer ViewSet-Unterklasse könnte ein guter Ort sein, um den Drehpunkt zu tun, sollten Sie den aktuellen Benutzer in self.request.user finden.

+1

Sie verdienen eine Verbesserung, weil ich am Ende alles implementiert, was Sie erwähnen (abgesehen vom Proxy-Modell). – newlog