Sie sind hier : sebastian1012.bplaced.net/ homepage-neu / kreuz-und-quer / tutorials-info-neuigkeiten-php / rechtesystem-a-la-unix.php

Rechtesystem à la UNIX

Bezugnehmend auf den Beitrag von crypt zum Thema Rechteverwaltung möchte ich heute eine andere Lösung vorstellen, die ohne Stored Procedures auskommt. Eigentlich zeige ich nur, wie man das UNIX- und Linux-Rechtesystem (chmod) in eigenen Projekten anwenden kann.

Crypt hat bereits gesagt, dass eine Extra-Spalte für jedes Recht enorme Speicherverschwendung ist. Wie so oft gilt: Der einfachste Weg ist selten der performanteste!

Worauf basiert das Rechtesystem von Unix nun eigentlich? Auf Zweierpotenzen und auf Addition. Beides lernt man bereits ganz zeitig in der Schule. Richtig angewendet kann es uns Programmierern aber das Leben stark vereinfachen.

Bei UNIX gibt es 3 Rechte: Lesen, Schreiben und Ausführen.
Diesen wird jeweils eine Zweierpotenz zugerechnet: Lesen=0; Schreiben=1; Ausführen=2.
„Ausgerechnet“ (=dezimal sowie hier auch oktal) ergebeben sich also Lesen=2^0=1; Schreiben=2^1=2 und Ausführen=2^2=4.

Um einem Benutzer (oder einer -gruppe) nun zum Beispiel die Rechte Lesen und Schreiben einzuräumen, ergibt sich 1+2=3. Lesen und Ausführen wäre 1+4=5. Eine einfache Addition also.

Es ist wichtig, dass hier Zweierpotenzen genutzt werden, sonst kann es zu Überschneidungen kommen. Würde man zum Beispiel einfach Lesen=1, Schreiben=2 und Ausführen=3 wählen, gäbe es bei den Rechten Lesen+Schreiben (1+2=3) und beim Recht Nur-Ausführen (=3) eine Überschneidung. Somit könnten wir nicht feststellen, welche Rechte der user denn nun wirklich hat. Mit den Zweierpotenzen kann das nicht passieren.

Nun übertragen wir das auf ein Beispiel mit 4 Rechten. Diese sind:

  1. User darf neue Beiträge schreiben
  2. User darf Beiträge löschen
  3. User darf Beiträge editieren
  4. User darf Beitrag lesen

Wir haben nun also 4 Rechte und können diesen Zweierpotenzen zuweisen:

Ein Administrator könnte nun beispielsweise alles dürfen (= 8+4+2+1 = 15). Ein angemeldeter User darf nur Schreiben und lesen (= 8+1 = 9). So kann man sich zu jeder Konstellation etwas zusammenbauen.

Wie wird das nun aber in der Datenbank umgesetzt?
Wir brauchen in der User-Tabelle eine Spalte rechte. Diese ist vom Typ TINYINT (gern auch UNSIGNED, das bringt noch etwas Performance). NOT NULL ist sie natürlich auch. Habe ich ja schon mal behandelt, warum das schneller ist. Damit haben wir potentiell 7 (= (ld 256)-1 -> ergibt sich aus: Maximum von 1 Byte = 8 1-Bits) mögliche Rechte (0 bedeutet immer keine Rechte). Wem das nicht reicht, wählt SMALLINT.

In diese können wir nun wie oben beschreiben die Werte einfügen. Um zu überprüfen, ob ein User ein bestimmtes Recht hat, tut man folgendes:

// Rechte-Wert des users aus Datenbank ist geholt $recht = 9; // Schreiben + Lesen   if($recht>=8) { // Schreiben erlaubt }   if(($recht>=4 && $recht<8) || $recht>=12) { // Löschen erlaubt }

Das sieht noch etwas amateurhaft aus, schließlich müsste man sich die Dezimalwerte, bei denen das Recht passt, erst mühsam zusammensuchen.
Einfacher geht es über binäre Operationen:

if(($recht & 8)==8) { // Schreiben erlaubt }   if(($recht & 4)==4) { // Löschen erlaubt }

Das wird bestimmt nicht auf den ersten Blick klar, deshalb erkläre ichs:
Über das &-Zeichen kann man eine binäre UND-Verknüpfung durchführen. Ich werde es am Beispiel des Rechtes Löschen aufdröseln:
Mögliche Dezimalwerte, die das Recht Löschen einschließen sind: 4, 5, 6, 7, 12, 13, 14, 15.
Was haben all diese Zahlen nun gemeinsam? Im dezimalen System nicht viel. Binär aber sieht die Geschichte anders aus. Hier nochmal die Zahlen binär: 0100, 0101, 0110, 0111, 1100, 1101, 1110, 1111.
Hier fällt auf, dass bei allen das 3. Bit (beachte: Zählung von rechts) 1 ist. Dieses Bit steht für 2^2=4 – und das wiederum ist genau unser gesuchtes Lösch-Recht.
Wir können nun jede dieser genannten Rechtekombinationen binär mit 0100 (=4) verknüpfen. Als Beispiel soll die 13 dienen:
1101 & 0100 = 0100
Mit allen genannten Kombinationen kommt das gleiche heraus.

Auf diese Art ist man auch sehr flexibel gegenüber Rechteerweiterungen, die später eventuell erfolgen sollen – und das möglichst ohne die gesamte Anwendung umzuschreiben.

Ich hoffe ich konnte dieses Rechtesystem etwas schmeckhaft machen und vielleicht denken Sie ja beim nächsten Mal, wenn Sie so etwas benötigen an diesen Beitrag.

PS: crypts Lösung ist etwas eleganter, weil man problemlos ein bestimmtes Recht setzen kann ohne die anderen zu kennen. Mit dem hier beschriebenen System müsste man den Wert in der Datenbank erst in eine Binärzahl umwandeln, dann das Recht ändern und anschließend wieder dezimal umrechnen. Sicherlich auch keine große Hürde – am Ende würde ein ähnliches System rauskommen wie bei crypt.
Der Vorteil des hier beschriebenen Systems ist die Entlastung der Datenbank (wichtig für Projekte, die dort den Flaschenhals haben).