Benutzerdefinierte Berechtigungen in Django: Beispiel von SDH

Aug 07, 2022 0 Minuten lesen 7160
Viacheslav Bukhantsov CEO & Co-Founder
Benutzerdefinierte Berechtigungen in Django: Beispiel von SDH

Das Django-Framework verfügt über ein eingebautes Berechtigungssystem, das für die meisten einfachen Projekte geeignet ist. Ich kann sagen, dass dies eine ideale Lösung für die eingebaute Admin-Schnittstelle ist. Was aber, wenn die Projektzugriffsrechte auf kompliziertere Weise implementiert werden sollen?

In diesem Artikel werde ich die Erfahrungen unseres Teams teilen und Ihnen einige Beispiele für die benutzerdefinierte Berechtigungs-Engine geben. Unser Beispiel wird nicht mit den eingebauten Berechtigungen von Django interferieren. Diesem Artikel liegt ein komplettes Django-Projekt mit der Implementierung bei. Um die Darstellung des Codes zu vereinfachen, habe ich bewusst die Zeilen entfernt, die sich auf aktives Query-Caching und Performance-Optimierung beziehen.

Das Demoprojekt wird auch für unerfahrene Entwickler nützlich sein, um es zu erkunden.

Unsere Praktiken für Django Groups & Permissions

Wir haben die erste Version des beschriebenen Ansatzes ab der Version Django 1.2 für das Projekt "Billing platform for ISP" eingesetzt. Die Anforderung des Projekts an die Sicherheit war die Differenzierung der Benutzerrechte zwischen verschiedenen Unternehmen. Die folgende Zusammenfassung gibt weitere Details:

  • Es können mehrere Firmen im System angelegt werden
  • Es gibt nur einen Eintrag für Benutzer (d.h. der Benutzer hat ein Login und Passwort in allen Firmen)
  • Die Zugriffsrechte in verschiedenen Firmen sind unabhängig, z.B. Benutzer A in Firma A ist Manager und kann die Daten von Kunde A (gehört zu Firma A) ändern, aber Benutzer A in Firma B hat nur Lesezugriff auf Kunde B (gehört zu Kunde B).

Wie aus der obigen Beschreibung der Anforderungen ersichtlich ist, muss die Umgehung der Zugriffsrechte auf Objektebene erfolgen.

Zur Übersichtlichkeit gebe ich eine kurze Beschreibung der Modelle:

 

class Firma(models.Model):
   Name = models.CharField(max_length=255)

   class Meta:
       db_table = 'Firma'


class Kunde(models.Model):
   Firma = models.ForeignKey(Firma, on_delete=models.PROTECT)
   name = models.CharField(max_length=255)

   class Meta:
       db_table = 'customer'

 

Im Projekt werden diese Modelle der Einfachheit halber in verschiedene Module aufgeteilt. Nehmen wir an, dass die Beschreibung der Berechtigung aus zwei Teilen besteht: dem Namen des Moduls und der Beschreibung der Benutzeraktion, die die Berechtigung steuern soll:

 

Modul

Aktion

Beschreibung

Firma

Lesen

Ansicht des Objekts Unternehmen

Firma

Erstellen

Anlegen des Objekts Firma

Firma

Aktualisierung

Änderung des Objekts Firma

Firma

Löschen

Löschen des Objekts Firma

Kunde

Lesen

Ansicht des Objekts Kunde

Kunde

Erstellen

Erzeugung des Objekts Kunde

Kunde

Aktualisierung

Änderung des Objekts Kunde

Kunde

Löschen

Löschen des Objekts Kunde

Kunde

Überprüfen

Verifizierung des Objekts Kunde

Kunde

Aktivieren

Aktivierung des Objekts Kunde

 

Nach der Tabelle sind einige der Aktionen "klassisches" CRUD, aber nur für die Anzeige; sowohl die realen Geschäftsanwendungen als auch das Berechtigungssystem sind komplizierter; zwei zusätzliche Funktionen wurden für das Kundenmodul hinzugefügt: zum Überprüfen und zum Aktivieren.
Beim Aufbau des Berechtigungssystems sind wir also nicht auf das CRUD-Modell beschränkt, sondern können die Benutzeraktionen mit der erforderlichen Granularität steuern.

Um den Code zu vereinfachen, werden die Rechte nur an Gruppen vergeben. In realen Projekten ist es manchmal erforderlich, Rechte für einzelne Aktionen auf Benutzerebene zu vergeben.

 

Zweistufige Struktur von Rechten

Die zweistufige Struktur von Berechtigungen wird durch die folgenden Modelle beschrieben:

 

class AccessModule(models.Model):
   name = models.CharField(max_length=128)
   slug = models.CharField(max_length=128, unique=True)

   class Meta:
       db_table = 'access_module'


class AccessPermission(models.Model):
   module = models.ForeignKey(AccessModule, on_delete=models.PROTECT)
   name = models.CharField(max_length=128)
   slug = models.CharField(max_length=128)
   groups = models.ManyToManyField(Group)

   class Meta:
       db_table = 'access_permission'
       unique_together = (('module', 'slug'),)

Das AccessPermission-Modell hat einen Hyperlink zu einer Gruppe. Auf diese Weise wird eine Liste von Gruppen identifiziert, die zu dieser Berechtigung berechtigt sind.

In dem ERP-Plattformprojekt können solche Modelle durch die folgende Konfigurationsschnittstelle dargestellt werden:


Custom Permissions in Django - ERP Platform Example

Im Ergebnis erscheint die Darstellung von Bereichen und Zugriffsrechten nach Benutzergruppen flexibel und benutzerfreundlich in der Funktionalität. Es muss lediglich ein Modell hinzugefügt werden, das beschreibt, zu welchen Gruppen ein Benutzer in verschiedenen Unternehmen gehört:


class AccessModule(models.Model):
   name = models.CharField(max_length=128)
   slug = models.CharField(max_length=128, unique=True)

   class Meta:
       db_table = 'access_module'


class AccessPermission(models.Model):
   module = models.ForeignKey(AccessModule, on_delete=models.PROTECT)
   name = models.CharField(max_length=128)
   slug = models.CharField(max_length=128)
   groups = models.ManyToManyField(Group)

   class Meta:
       db_table = 'access_permission'
       unique_together = (('module', 'slug'),)

 

Das Objekt HttpRequest ist in vielen Kontexten vorhanden: es kann in View gefunden werden, es kann in den Template-Kontext übertragen werden. Informationen über den autorisierten Benutzer sind auch in request.user verfügbar.

Daher wäre es praktisch, den Zugriff auf die Rechteprüfung über Request hinzuzufügen. Zu diesem Zweck wurde eine Middleware entwickelt, die ein lazy object zu Acl ist.

Beispielsweise ist es möglich, folgende Konstruktion zu verwenden:

def get_queryset(self):
   qs = super().get_queryset()
   qs = qs.filter(company__in=self.request.acl.get_companies('customer', 'view'))
   return qs

Das obige Beispiel zeigt, dass die Kundenliste nur nach Unternehmen gefiltert wird, für die der Benutzer Rechte hat.

Es wird dringend empfohlen, sich das Beispiel von CustomerListView aus dem Projekt anzusehen.

In diesem Artikel bin ich nicht auf das aktive Caching von Anfragen nach Rechten eingegangen. Wie Sie aus dem Code ersehen können, ist das Hinzufügen von Caching nicht schwierig, wenn Sie einen Caching-Schlüssel auf die folgende Weise zusammenstellen:

<module_slug>:<permissions_slug>:<company_id>

In meinen nächsten Arbeiten wird ein Beispiel und eine Beschreibung der Verwendung dieser Permission Engine in Kombination mit dem Django Rest Framework durchgeführt, sowie die automatische Dokumentation von Permissions in Verbindung mit drf-spectacular vorgestellt werden.

Software Development Hub ist ein in der Ukraine ansässiges Softwareentwicklungsunternehmen mit Python/Django-Stack. Wir helfen technikbegeisterten Unternehmen, ihre Wachstumsziele durch Outsourcing von IT-Talenten zu erreichen. Mit einem Pool von mehr als 100 hochqualifizierten Spezialisten kann SDH Engineering-Einheiten mit nahezu jedem Skillset aufbauen und bietet so maximale Flexibilität, um qualitativ hochwertige Softwareentwicklungsdienste für Projekte jeder Komplexität und Größe zu liefern.

 

 

Categories

Python-Software-Development

Share

Benötigen Sie einen Projektkostenvoranschlag?

Schreiben Sie uns, und wir bieten Ihnen eine qualifizierte Beratung.

x
Partnership That Works for You

Your Trusted Agency for Digital Transformation and Custom Software Innovation.