PHP Datenbank-Entwurf für einen Mitgliederbereich mit mehreren Recht

Blackbenji

Lieutenant
Registriert
Nov. 2009
Beiträge
565
Hallo,

Grundlegend habe ich mich versucht an dem Tutorial http://tut.php-quake.net/de/admin.html zu halten.

Allerdings fehlt mir hier die Möglichkeit den 'Gruppen' einzelne Rechte hinzuzufügen. Speziell geht es darum, wer innerhalb des CMS mit seinen Rechten was machen darf.
User zb nur Kommentare Schreiben, Authoren dürfen aber News schreiben.

In einem Gedankenversuch habe ich dann jede Option in die Datenbank geschrieben, was dann um die 36 Spalten waren ...

Warum so komplilziert? Ich möchte das ein Admin selber Gruppen anlegen kann und zu jeder Gruppe eigene Rechte verteilen darf.

Nur wie stellt man sowas sinnvoll ein, ohne 36 Abfragen zu machen, ob er das Recht hat oder nicht?
 

Anhänge

  • Bildschirmfoto 2012-11-03 um 13.43.08.png
    Bildschirmfoto 2012-11-03 um 13.43.08.png
    15,6 KB · Aufrufe: 158
Bastel dir doch ein enum draus.
Code:
<?php

class Rights
{
	protected $Rights;
	
	static protected $FlagRead = 1;
	static protected $FlagWrite = 2;
	static protected $FlagCreate = 4;
	static protected $FlagDelete = 8;
	
	public function CanRead() { return ($this->Rights & self::$FlagRead) != 0; }
	public function CanWrite() { return ($this->Rights & self::$FlagWrite) != 0; }
	public function CanCreate() { return ($this->Rights & self::$FlagCreate) != 0; }
	public function CanDelete() { return ($this->Rights & self::$FlagDelete) != 0; }
	
	public function GrantRead() { $this->Rights |= self::$FlagRead; }
	public function GrantWrite() { $this->Rights |= self::$FlagWrite; }
	public function GrantCreate() { $this->Rights |= self::$FlagCreate; }
	public function GrantDelete() { $this->Rights |= self::$FlagDelete; }
	
	public function RevokeRead() { $this->Rights &= ~self::$FlagRead; }
	public function RevokeWrite() { $this->Rights &= ~self::$FlagWrite; }
	public function RevokeCreate() { $this->Rights &= ~self::$FlagCreate; }
	public function RevokeDelete() { $this->Rights &= ~self::$FlagDelete; }
	
	public function __construct( $Read, $Write, $Create, $Delete )
	{
		$this->Rights = 0;
		$this->Rights |= $Read ? self::$FlagRead : 0;
		$this->Rights |= $Write ? self::$FlagWrite : 0;
		$this->Rights |= $Create ? self::$FlagCreate : 0;
		$this->Rights |= $Delete ? self::$FlagDelete : 0;
		// ...
	}
}

class RightsNews extends Rights {}
class RightsComments extends Rights {}
// ...
Dann hast du pro Bereich eine Spalte (int) in der DB und kannst in dieser aber die Rechte einfach verteilen.
 
Zuletzt bearbeitet: (Klasse erweitert)
Schon mal an ne Bitfolge gedacht?
Jedes Bit steht für eine bestimmte Berechtigung. Und herauszufinden, ob ein bestimmter User eine bestimmte Menge an Berechtigungen hat, verUNDe die Berechtigungsbitfolge mit einer Bitmaske, die die gesuchte Menge an Berechtigungen repräsentiert. Wenn das Ergebnis gleich der Bitmaske ist, dann hat der User mindestens die gesuchten Berechtigungen.

Gruß Timo
 
Hallo Yuuri,

danke, das sieht sehr komplex aus und mir warscheinlich noch eine Nummer zu hoch.
Kannst Du mir vielleicht ein Aufrufbeispiel noch geben, mit dem ich die Klasse besser verstehen kann?

Danke!
 
Du kennst doch die Grundregel: Schreibe nichts selbst, was jemand anderes bereits verdammt gut implementiert und zur freien Verwendung gestellt hat.
Mit anderen Worten: Schnapp dir ein Open Source CMS mit gutem Rechtemanagement (da kann ich dir nur Contao empfehlen, unterliegt LGPL) und lass dich davon inspirieren. Du wirst in mehreren Wochen und Monaten Arbeit auch nichts besseres bewerkstelligen als das, was die guten bestehenden Systeme nicht bereits können. Investiere deine Zeit also lieber in andere Aspekte, die diese Systeme nicht bieten.
 
Die Methodennamen sagen doch eigentlich schon alles aus. Obige Klasse mal für die einfache Verwendung mit der DB abgeändert:
Code:
class Rights
{
	// ...
	public function __construct( $Read = false, $Write = false, $Create = false, $Delete = false )
	{
		if( is_numeric( $Read ) && $Write === false && $Create === false && $Delete === false ) // Zahl aus DB bekommen
			$this->Rights = (int)$Read;
		else // Werte einzeln setzen
		{
			$this->Rights = 0;
			$this->Rights |= $Read ? self::$FlagRead : 0;
			$this->Rights |= $Write ? self::$FlagWrite : 0;
			$this->Rights |= $Create ? self::$FlagCreate : 0;
			$this->Rights |= $Delete ? self::$FlagDelete : 0;
		}
		// ...
	}
	// ...
}

$q = "
SELECT *
FROM rights
WHERE user_id = 1
";
$q = mysql_fetch_array( mysql_query( $q ) );
$_SESSION['rights'] = array(
	'news' => new Rights( $q['news'] ),
	'links' => new Rights( $q['links'] ),
	// ...
);

if( $_SESSION['rights']['news']->CanWrite() )
{
	// erlaube News zu schreiben
}

if( $_SESSION['rights']['links']->CanDelete() )
{
	// erlaube Links zu löschen
}

$_SESSION['rights']['news']->GrantWrite(); // erlaube News zu schreiben
$_SESSION['rights']['links']->RevokeDelete(); // entziehe das Recht Links zu löschen
Stell dir $Rights mal als binäre Darstellung vor.
Code:
Stellenwert 1 2 4 8 16 32 64 128 ...
Wert        0 0 0 0  0  0  0   0 ...
Stelle 1 sagt uns, dass es das Recht gibt, etwas zu lesen. 2, dass wir etwas schreiben können usw. Mit der Oder-Verknüpfung (Grant*-Funktionen), setzt du nun den Status entsprechend dem übergebenen Wert.
$FlagDelete bspw. besitzt den Wert 8, also schreiben wir an obigen Stellenwert 8 eine 1.
Code:
Stellenwert 1 2 4 8 16 32 64 128 ...
Wert        0 0 0 1  0  0  0   0 ...
Damit erhalten wir nun den Status, dass der User nichts darf, außer etwas zu löschen. Mit Und (&) prüfst du, ob ein Wert gesetzt ist. Um einen Wert zu löschen, negierst du die Zahl (~) und verknüpfst sie mit Und.

Siehe auch Wahrheitswertetabelle: http://de.wikipedia.org/wiki/Konjunktion_(Logik)

Stells dir im Prinzip so vor: Statt mehrere Variablen zu besitzen, die alle vom Typ bool sind, packst du alles kompakt in eine einzige Variable mit entsprechendem Vorteil des Speicherplatzes und Wartungsaufwandes.
 
Also mit Datenbanken kannst du die Rechte entweder als set oder als Tabelle anlegen.
Also ich komm dann auf 5 Tabellen:
user
map_user_group
group
map_group_premission
permission
Und wenn du dann wissen willst, ob jemand ein Recht hat:
Code:
select 1 from user join map_user_group join group join map_group_permission join permission where permission='edit' and user='hans'
Und wenn du alle Rechte haben willst, lässte einfach "where permission='...' " weg

Und eure Bitfolgen: Genauso setzt es MySQL z.B. um wenn man ein SET erstellt.
 
Zurück
Oben