![]() |
| | LinkBack | Themen-Optionen | Thema durchsuchen |
| | Nach oben #1 |
| Jann Hendrik Bekaan Registriert seit: 02.12.2004 Ort: Wildeshausen
Beiträge: 3.198
|
Ich möchte ein Gruppenbasiertes Rechtesystem in einer Datenbank verwalten. Dabei soll es verschiedene Dinge geben, die eingestellt werden sollen, was man machen darf. Dann soll es verschiedene Gruppen geben, die verschiedene Dinge aus der Rechte-Liste zugewiesen bekommen können, was sie dürfen und was nicht. Jeder user wird dann einer oder mehr Gruppen zugewiesen, worduch sich seine Rechte ergeben. Soweit eigentlich nichts spektakulär neues - nur für mich ist das was neues Ich denke, dass ich das ganze soweit normalisiert habe (was man ja machen soll). Ich habe eine Tabelle mit usern, in der die wichtigen Daten enthalten sind: Name, Passwort, E-Mail-Adresse usw. Hier mal nur der wichtige Auszug aus der Tabelle: Code: +------------------------------+ | user | +------------------------------+ | ID | name | password | +----+--------------+----------+ | 1 | Jann Hendrik | abc | | 2 | pago | def | | 3 | noch jemmand | ghi | | .. | ... | ... | +----+--------------+----------+ Code: +--------------------+ | groups | +--------------------+ | ID | groupname | +----+---------------+ | 1 | bloger | | 2 | user | | 3 | moderator | | 4 | administrator | | .. | ... | +----+---------------+ Code: +-------------------------+ | user_in_groups | +-------------------------+ | ID | user_ID | group_ID | +----+--------------------+ | 1 | 1 | 1 | | 2 | 1 | 3 | | 3 | 5 | 2 | | 4 | 2 | 1 | | .. | ... | ... | +----+--------------------+ Code: +-----------------+ | permission | +-----------------+ | ID | permission | +----+------------+ | 1 | darf_a | | 2 | darf_b | | 3 | darf_c | | 4 | darf_d | | .. | ... | +----+------------+ Code: +-------------------------------+ | group_permission | +-------------------------------+ | ID | group_ID | permission_ID | +----+----------+---------------+ | 1 | 1 | 1 | | 2 | 4 | 2 | | 3 | 3 | 1 | | 4 | 1 | 2 | | .. | ... | ... | +----+----------+---------------+ Wenn nicht, dann hätte ich dazu nämlich ein paar Fragen. Ich möchte wenn sich nun ein user einlogt eine session starten, in der sämtliche Rechte abgespeichert sind. Auf der jeweiligen Seite die ihm dann angezeigt wird, sofern er die Rechte hat, wird dann eine entsprechende Abfrage gestartet, ob der user auch wirklich die Rechte für diese Seite hat à la PHP-Code: Ich habe gerade keine Idee, wie ICH die 5 Tabellen sinnvoll verbinden kann. Die Thematik JOIN bei mysql habe ich bisher immer vermieden, weil ich das bisher nicht verstanden habe. Mir scheint aber so, als wäre das nun mal an der Zeit....
__________________ Umfragen: Wenn du dich in ein interessantes Thema eingearbeitet hast, dann lass andere daran teilhaben! Danke! |
| | |
| | Nach oben #2 | ||
| Erfahrener Benutzer Registriert seit: 18.03.2005
Beiträge: 696
| Zitat:
Wenn der Benutzer jedoch nur einer Gruppe zugeteilt wird, dann kann man die group_ID auch gleich in die User-Tabelle schreiben und spart man sich schon ein Query. Bei diversen Projekten von mir, ist das unter user_level definiert. Die jeweilige SESSION kann ja ein Array sein, was alle group_IDs enthält. $_SESSION['level']['darf_a'] $_SESSION['level']['darf_b'] etc... Muss dann natürlich immer abgefragt werden. Zitat:
| ||
| | |
| | Nach oben #3 |
| Jann Hendrik Bekaan Registriert seit: 02.12.2004 Ort: Wildeshausen
Beiträge: 3.198
| Das mag sein - aber diese Flexibilität möchte ich mir nicht nehmen. Ich halte es in diesem Falle für vorteilhaft, wenn user x in Gruppe a, b und c sein kann auch wenn es eine kleine Performance-Bremse darstellen sollte. Das wird kein Projekt wo zig user gleichzeitig drauf zugreifen werden, so dass ich denke, dass das vertretbar sein dürfte. In der Session selbst wollte ich das in etwa so abspeichern PHP-Code: Alternativ könnte ich auch erst auf der Seite die SQL-Abfrage machen, was ich aber dann doch lieber über das array cachen möchte. In Abhängigkeit des arrays möchte ich nämlich auch die Navigation darstellen. Die Bereiche, für die der jeweilige user keine Rechte hat, die sollen ihm auch in der Navigation verborgen bleiben. Somit wäre es (finde ich) schon sinnvoll das Rechte-System in dem array abzuspeichern, damit man dann nicht bei jedem Aufrauf wieder die DB-Abfrage starten muss.
__________________ Umfragen: Wenn du dich in ein interessantes Thema eingearbeitet hast, dann lass andere daran teilhaben! Danke! Geändert von Jann Hendrik (18.10.2008 um 12:07 Uhr) |
| | |
| | Nach oben #5 |
| Johannes Müller Registriert seit: 15.09.2005 Ort: Königreich Flieden
Beiträge: 693
|
Die Berechtigungen in der Session zu speichern ist eigentlich ziemlicher standard und funktioniert auch ganz gut. Ggf. müsste man sich nur was überlegen, wie die gespeicherten Rechte erneuert werden können, wenn ein Administrator irgendwelche Rechte ändert während gerade ein User eingeloggt ist und diese Änderung nicht erfahren würde. Also für die Anzeige etc. ist das sicherlich nicht so schlimm, sobald aber irgendwelche Änderungen durchgeführt werden, wäre ein live-abgleich mit der Datenbank praktisch, um zu überprüfen, ob die Rechte wirklich noch vorhanden sind. Das wäre nur ein Ansatz, es könnte auch so gemacht werden, dass bei ner Änderung der Berechtigungen irgendwie alle Session-Daten gelöscht werden, damit sie beim nächsten Seitenaufruf eines Users wieder neu aus der DB geholt werden. Bei deinen Tabellen besteht unter Umständen noch Optimierungspotential. Die Tabelle user_in_groups benötigt keine ID, da durch die beiden Keys jeder Zeile eindeutig benannt ist. Möglicherweise könntest du dir die Tabelle, ähnlich wie beim Vorschlag von CIX, auch ganz sparen, indem du eine Spalte groups in der user-Tabelle anlegst, die ein Array aller Gruppen-IDs enthält, denen der User angehört. Dadurch geht die primäre Abfragerichtung "User -> Gruppen" etwas schneller (da ein Query gespart), die Abfrage "Gruppe -> Users" ist dagegen relativ selten (wird eigentlich nur für die Mitgliederübersicht einer Gruppe benötigt), also macht es nichts, wenn die ein bischen langsamer ist. Wobei ich garnicht mal weiß, ob das soo viel dann ausmacht. Als nächstes stellt sich mir die Frage, ob die Tabelle permission überhaupt notwendig ist. Sie dient ja eigentlich nur dazu, in MySQL irgendwelche Konstanten festzulegen. Bei einer vernünftigen Programmierung müssten diese Konstanten als Bezeichner für eine Berechtigung aber auch im Programm definiert sein, daher ist in der Datenbank nur eine unnötige Doppelung, die noch mehr Aufwand macht. Dann ist nämlich auch group_permission unnötig und es geht ganz einfach mit einer Spalte permissions in der Tabelle groups, in der durch Kommata getrennt die einzelnen Rechte stehen. Interessant ist es bei solchen Designentwürfen auch immer, sich mal anzusehen, wie das in anderer Software gelöst wird. Ich habe jetzt grad keine DB zur Verfügung, aber ich meine, dass z.B. Drupal das so ähnlich macht, dass die zugewiesenen Rechte einfach als Namen in einer Spalte in der Tabelle User bzw. Gruppe stehen. Noch ein paar kleinere Sachen: Warum sind alle Tabellennamen im Singular, nur groups im Plural? Das Password wird in Wirklichkeit doch als Hash gespeichert, oder?
__________________ Weißt Bescheid - Scheiß wie weit |
| | |
| | Nach oben #6 | |||||||
| Jann Hendrik Bekaan Registriert seit: 02.12.2004 Ort: Wildeshausen
Beiträge: 3.198
| Zitat:
Zitat:
Was man machen könnte ist der Session noch einen Zeitstempel aufdrücken. Wenn dann die Startseite besucht wird und der Zeitstempel zu alt, dann werden die Session-Daten neu geschrieben. Bei mir reicht es aber völlig aus, wenn der entspr. user sich einmal aus- und später wieder einlogen muss. Zitat:
Zitat:
Wenn ich es mir aussuchen darf, dann würde ich bei dem bisherigen Designvorschlag bleiben wollen. Zitat:
Zitat:
Ich bin auf den Aufbau gekommen, weil ich mir überlegt habe, wie es gelöst sein könnte, weil ich weiß, welche Flexibilität es dadurch erlaubt. Gerade das ist ein Punkt, der in der Rechteverwaltung zB dieses Forums von mir sehr geschätzt wird. Durch den Aufbau der Datebank jedoch steige ich nicht ausreichd gut durch, als das ich sagen könnte, dass es reicht mir diesen Teil davon abschauen zu können. Zitat:
Das Passwort - das ist bereits der hash ;) Nein, natürlich ist er das nicht... die werden nicht im Klartext gespeichert. Damit wollte ich mich aber separat beschäftigen. In der user-Tabelle stehen noch einige Daten mehr drin, die aber hierfür nicht relevant sind.
__________________ Umfragen: Wenn du dich in ein interessantes Thema eingearbeitet hast, dann lass andere daran teilhaben! Danke! | |||||||
| | |
| | Nach oben #7 | |
| Erfahrener Benutzer Registriert seit: 12.06.2006
Beiträge: 335
| Zitat:
Das Frontend behandelt das glaub so: Ein Inhaltselement (das dann bestimmte Aktionen ermöglicht) bekommt ein paar Gruppen-IDs zugewiesen; diese werden mit den Gruppen-IDs des Nutzers verglichen. Wenn es Übereinstimmungen gibt, wird das Element angezeigt. | |
| | |
| | Nach oben #8 | |||||
| Johannes Müller Registriert seit: 15.09.2005 Ort: Königreich Flieden
Beiträge: 693
| Zitat:
Es mag zunächst vielleicht etwas befremdlich klingen, ein Arrayfeld in einer Tabelle zu verwenden, aber: Was ist denn so schlimm dran?? Man muss nicht alle Daten, die irgendwie in einer Listen- oder Tabellenform vorliegen zwanghaft in eine eigene Datenbanktabelle packen, wenn das überhaupt nicht erfoderlich ist; nur das meint man beim Design einer Datenbank meistens^^ Wenn man sich, wie oben schon angesprochen, mal andere Software anguckt, findet man es sehr oft, dass Daten, für die man auf den ersten Blick in eine eigene Tabelle erwarten würde, einfach irgendwo als Array in eine Spalte gespeichert sind, weil es einfach nicht notwendig ist eine Tabelle anzulegen, wenn in den meisten Fällen sowieso eine Abfrage aller Elemente des Array erfolgt und eine (einzelne) Rückverfolgung (in welchem Datensatz befindet sich der Wert XY) eher selten ist. Zitat:
Ausgehend von der Gruppenid hast du zum Abfragen aller Berechtigungen einer Gruppe (in Form des Namens "darf_X") folgenden Weg: Code: <Gruppe>:group.group_ID -> group_permission.group_ID | group_permission.permission_ID -> permission.ID | permission.permission:<Permission> Das ganze ist viel einfacher, wenn bei einer einzigen Abfrage von groups bereits alle Berechtigungen als Array zurückgeliefert werden, genau so brauchst du es doch auch für dein Skript und das Caching in der Session. Zitat:
Wenn wir beispielsweise eine Berechtigung darf_editieren haben, entspricht das den Datenbankänderungen (und somit beim System von TYPYlight einzelnen Berechtigungen) der Felder article.name, article.body, article.lastModified. darf_erstellen entspricht article.id, article.name, article.body, article.created, article.lastModified. Und das sind noch relativ wenige Datenbankänderungen, die bei vielen anderen CMS mit einer einzigen Aktion (und der Berechtigung dazu) ausgeführt werden.
__________________ Weißt Bescheid - Scheiß wie weit Geändert von $traight-$hoota (18.10.2008 um 16:49 Uhr) | |||||
| | |
| | Nach oben #9 | |
| Erfahrener Benutzer Registriert seit: 18.03.2005
Beiträge: 696
| Zitat:
Es sei denn, du benutzt eine andere Möglichkeit unterschiedliche Gruppen in einen Datensatz zu erfassen. | |
| | |
| | Nach oben #10 | ||
| Johannes Müller Registriert seit: 15.09.2005 Ort: Königreich Flieden
Beiträge: 693
| Zitat:
user.ID und group.ID sind jeweils Primary Keys und daher auch als Foreign Keys in user_in_group jeweils eindeutig. Über die nur einmal mögliche Kombination gleicher Keys user_ID und group_ID ergibt sich somit eine eindeutige Benennung jedes Datensatzes. Großartiges Verwalten sollte es da nicht geben, sondern lediglich das Hinzufügen eines Users zu Gruppe (neuer Datensatz mit den beiden IDs) und das Entfernen eines Users aus einer Gruppe (Datensatz mit den beiden IDs löschen).
__________________ Weißt Bescheid - Scheiß wie weit | ||
| | |
| | Nach oben #11 | |
| Erfahrener Benutzer Registriert seit: 12.06.2006
Beiträge: 335
| Zitat:
Beispiel: Redakteure bekommen das Recht, Inhalte, Überschriften etc. einzutragen, aber veröffentlich können sie einen Artikel nicht. Das kann dann aber der Chefredateur. Sowas ist mit TL fix eingerichtet ;). Einmal gibt es die "allgemeinen" Zugriffsrechte auf die Module/Extensions/Einstellungen etc, diese entsprechen dem Lesezugriff. Dann definiert man in den Gruppen nochmal die editierbaren Felder. Mag sein, dass an einer Stelle des Codes dann ein kleiner Overhead ensteht, aber an anderen Stellen wird somit jede Menge eingespart! Bei der Extension-Entwicklung z.B. muss man kaum Code schreiben (hauptsächlich die Beschreibungsarrays definieren). Rest läuft automatisch ab. Schau es dir einfach mal an, ich kann es nicht so gut beschreiben. Edit: Wo hast du z.B. kompliziertere Aktionen in einem Schritt? Sowas wird doch eh meist über mehrere Seiten verteilt ... dir ist bewusst, dass wir von Website-Verwaltungapplikationen reden ;) ? Zu den Arrays: Kann ich meinen Vorrednern nur zustimmen. Arrays kann man prima in DBs legen. Einfach serialisieren und in ein BLOB damit. Geändert von FloB (18.10.2008 um 17:11 Uhr) | |
| | |
| | Nach oben #12 | |
| Erfahrener Benutzer Registriert seit: 18.03.2005
Beiträge: 696
| Zitat:
Ich arbeite auch gerne mit primären IDs die völlig getrennt vom jeweiligen Datensatz sind. Einmal nicht aufgepasst, und schon wurde der falsche Datensatz erwischt :) Nene, dem beuge ich vor :) Sicher kann man darauf verzichten, jedoch bei mir hat sich das so angeeigent :) Aber um so mehr ich darüber nachdenke (spätere Verwaltung etc..) kann man sicher daruf verzichten. | |
| | |
| | Nach oben #13 |
| Jann Hendrik Bekaan Registriert seit: 02.12.2004 Ort: Wildeshausen
Beiträge: 3.198
|
Okay, nach dem für und wider würde ich sagen, dass ich trotz der Vorschläge dabei bleibe das DB-Design so aufzubauen. Ich vermute mal, dass ich mir eine Monster-SQL-Abfrage bauen muss, wo die verschiedenen keys ineinander greifen mit verschiedenen inner/outer und sonstwas-joins, oder? Ich denke, ich würde das auch mit geschätzten 400 einzelnen queries hinbekommen, aber... dann würde ich ja nicht fragen :) Ich will ja dabei auch noch was lernen. Mag mir jemand Anschub-Hilfe geben?
__________________ Umfragen: Wenn du dich in ein interessantes Thema eingearbeitet hast, dann lass andere daran teilhaben! Danke! |
| | |
| | Nach oben #14 | |
| Christian W. Achatz Registriert seit: 05.02.2007 Ort: München
Beiträge: 198
|
Hallo Jann, Zitat:
Code: SELECT ent_user.* FROM ent_user INNER JOIN cmp_application2user ON ent_user.UserID = cmp_application2user.UserID INNER JOIN ent_application ON cmp_application2user.ApplicationID = ent_application.ApplicationID WHERE ent_application.ApplicationID = '1' ORDER BY ent_user.LastName ASC, ent_user.FirstName ASC; Hier noch die relevanten Links: * http://adventure-php-framework.org/S...aden-von-Daten * http://forum.adventure-php-framework...c.php?f=5&t=54 * http://adventurephpfra.svn.sourcefor...sermanagement/ Solltest du Fragen dazu haben, dann her damit! :)
__________________ Viele Grüße, Dr.E. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Think about software design before you start to write code! 2. Discuss and review it together with experts! 3. Choose good tools (-> http://adventure-php-framework.org)! 4. Write clean and reusable software only! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| | |
| | Nach oben #15 |
| Jann Hendrik Bekaan Registriert seit: 02.12.2004 Ort: Wildeshausen
Beiträge: 3.198
| Die werden sehr wahrscheinlich kommen! Aber erstmal versuche ich die Infos zu verdauen. Ggf. komme ich dann ja schon einen Schritt weiter ... :)
__________________ Umfragen: Wenn du dich in ein interessantes Thema eingearbeitet hast, dann lass andere daran teilhaben! Danke! |
| | |
| | Nach oben #16 |
| Jann Hendrik Bekaan Registriert seit: 02.12.2004 Ort: Wildeshausen
Beiträge: 3.198
|
Also, ich habe meine Beispiel-Tabelle nun mal mit Daten gefüllt. Für den Anfang darf jeder user nur in einer Gruppe sein und jeder Gruppe darf nur eine Sache machen. Für diesen Fall hätte ich das zwar auch direkt in die user-Tabelle schreiben können - aber... ich will mal klein anfangen. Mit Code: SELECT
`user`.`ID`,
`user`.`name`,
`user`.`password`,
`user`.`mail`,
`groups`.`groupname`,
`permissions`.`permission`
FROM
`user`
INNER JOIN
`user_in_group`
ON
`user`.`ID` = `user_in_group`.`user_ID`
INNER JOIN
`groups`
ON
`user_in_group`.`ID` = `groups`.`ID`
INNER JOIN
`group_permission`
ON
`groups`.`ID` = `group_permission`.`ID`
INNER JOIN
`permissions`
ON
`permissions`.`ID` = `group_permission`.`ID`
WHERE
`user`.`ID` = 1
Allerdings stoße ich damit auf mein erstes Problem. Wenn ein user in mehr als nur einer Gruppe ist funktioniert das insofern nicht mehr, als dass nicht alle Gruppen (nur eine) angezeigt werden. Ebenso auch, wenn eine Gruppe mehr als nur eine permission hat. Dann wird auch nur eine angezeigt. Wenn ich die Rechte des users mit der ID 1 auslesen möchte, sollten aber alle dargestellt werden: Code: SELECT `permissions`.`permission` FROM `user` INNER JOIN `user_in_group` ON `user`.`ID` = `user_in_group`.`user_ID` INNER JOIN `groups` ON `user_in_group`.`ID` = `groups`.`ID` INNER JOIN `group_permission` ON `groups`.`ID` = `group_permission`.`ID` INNER JOIN `permissions` ON `permissions`.`ID` = `group_permission`.`ID` WHERE `user`.`ID` = 1 Code: +------------+ | permission | +------------+ | darf_a | | darf_c | | darf_r | +------------+ Deinen drei links konnte ich leider nichts verwertbares entnehmen. Das liegt ggf. aber auch an mir :)
__________________ Umfragen: Wenn du dich in ein interessantes Thema eingearbeitet hast, dann lass andere daran teilhaben! Danke! |
| | |
| | Nach oben #17 |
| Christian W. Achatz Registriert seit: 05.02.2007 Ort: München
Beiträge: 198
|
Hallo Jann, das ist so ein bischen eine Frage der Philosophie. Im APF usermanagement habe ich das konzeptionell so gelöst, dass du dir erst mal einen Benutzer selektierst und diesen dann nach seinen Rechten fragst. In einer Abfrage abgebildet kannst du das auf Grund der Beziehungen aber auch selektieren. Es muss in diesem Fall jedoch sichergestellt sein, dass deine Datenschicht diese Datenkonsistent gewährleistet. Um vom gleichen zu sprechen, nehmen wir mal folgendes UML als Basis: http://adventure-php-framework.org/S...aden-von-Daten Dort steht beschrieben, dass eine Rolle und eine Gruppe jeweils "seinen" Benutzer kennt (Assoziation). Weiterhin kennt die Rolle "sein" PermissionSet, das wiederum seine Permissions komponiert. In diesem Fall würdest du die Permissions eines Benutzers über ungefähr folgendes Statement selektieren können: Code: SELECT ent_permission.* FROM ent_permission INNER JOIN cmp_permissionset2permission ON ent_permission.PermissionID = cmp_permissionset2permission.PermissionID INNER JOIN ent_permissionset ON cmp_permissionset2permission.PermissionSetID = ent_permissionset.PermissionSetID INNER JOIN ass_role2permissionset ON ent_permissionset.PermissionSetID = ass_role2permissionset.PermissionSetID INNER JOIN ent_role ON ass_role2permissionset.RoleID = ent_role.RoleID INNER JOIN ass_role2user ON ent_role.RoleID = ass_role2user.RoleID INNER JOIN ent_user ON ass_role2user.UserID = ent_user.UserID WHERE ent_user.UserID = 1; Jetzt klar?
__________________ Viele Grüße, Dr.E. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Think about software design before you start to write code! 2. Discuss and review it together with experts! 3. Choose good tools (-> http://adventure-php-framework.org)! 4. Write clean and reusable software only! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | Nach oben #18 |
| Jann Hendrik Bekaan Registriert seit: 02.12.2004 Ort: Wildeshausen
Beiträge: 3.198
|
Okay, ich realisiere, dass ich dafür gerade nicht die notwendige Ruhe habe... Ich werde mich demnächst nochmal an das Thema machen.
__________________ Umfragen: Wenn du dich in ein interessantes Thema eingearbeitet hast, dann lass andere daran teilhaben! Danke! |
| | |
![]() |
| Lesezeichen |
| Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1) | |
| Themen-Optionen | Thema durchsuchen |
| |
Ähnliche Themen | ||||
| Thema | Autor | Forum | Antworten | Letzter Beitrag |
| Gruppierte Rechteverwaltung mittels PHP und MySQL | Chr!s | PHP-Programmierung | 18 | 18.10.2006 14:06 |