Klassen, API und Rechte - was, wann, wo prüfen

mercsen

Lt. Commander
Registriert
Apr. 2010
Beiträge
1.658
Moin,

ich sitze erneut an einem Projekt und befinde mich aktuell in der entwurfsphase. Es gibt da eine Frage die mich schon länger beschäftigt.
Zuerst um was es geht:
Ich baue eine restful API (basierend auf PHP). Um den Code sauber zu halten gibt es für die einzelnen Resourcen Klassen, z.B. die Klasse Customer. Aktuell sieht mein entwurf so aus, das eine Klasse vollkommen egal von den berechtigungen des Users einfach das macht wofür sie gedacht ist, nämlich die Daten aus der Datenbank holen und in einem Objekt zu speichern, sowie die Daten zu manipulieren und am Ende zurück in die Datenbank zu schreiben.
Die Rechteverwaltung findet dann in den API scripten statt.

Also der Client ruft eine Adresse auf, meinetwegen etwas wie /rest/customer/3.
Durch diesen Aufruf wird dann das API Script ausgeführt welches seinerseits ein Objekt der Klasse Customer instanziiert. Das API Script prüft vorher allerdings ob der User dazu berechtigt ist.

Der Vorteil: Die Klasse selber muss sich um nichts kümmern, hat keinerlei Abhängigkeiten zu anderen Objekten und kann einfach ihr Leben chillen.
Der Nachteil: Wann immer ich die Klasse nutzen will, muss ich vorher auf die Berechtigung prüfen. Und die API muss auch noch entsprechend reagieren, ich habe also einigen Code "doppelt"

Wie löst ihr so ein Problem? Würde es sinn machen die Rechtverwaltung in die Klasse zu übernehmen? Im endeffekt existiert ohnehin ein Super Globales Objekt der Klasse PermissionManager über die man mit 2 Parametern (welches modul und welches recht) abfragen kann ob der Zugriff gestattet ist.

Zudem kann der Fall auftreten das ein User bestimme Felder nicht sehen, bzw. nicht bearbeiten darf. Lasse ich das einfach von der API filtern oder sollte die Klasse das von vornherein selber erledigen?

Löse ich die Rechteverwaltung aber in der Klasse muss das Objekt aber auch entsprechend reagieren können wenn ein Recht mal verweigert wird und die ganzen Methoden aufrufe verkomplizieren sich :-/
Wäre natürlich leichter wenn die API den aufruf der methode einfach gar nicht zulässt.
 
Zuletzt bearbeitet:
Zudem kann der Fall auftreten das ein User bestimme Felder nicht sehen, bzw. nicht bearbeiten darf. Lasse ich das einfach von der API filtern oder sollte die Klasse das von vornherein selber erledigen?
Das klingt mir eher danach das Du mit Views arbeiten solltest und die Berechtigungen in der DB sauber hinterlegen.
Rechteverwaltung getrennt halten, User Credentials immer mit an die DB-Klasse geben und SQLs nicht direkt in den Klassen ausführen, sondern immer über Funktionen eine DB-Klasse laufen lassen wäre da eher mein Ansatz, macht auch die Fehlerbehandlung einfacher.
 
Bin mir nicht ganz sicher wie du das meinst.
Ich habe eine MySQL Klasse die von mysqli erbt und entsprechend alles ausführt. Dein Ansatz wäre aber ich hole mir die Daten aus der Datenbank und gebe diese dann an eine Klasse weiter?

sowas wie (pseudocode)

Code:
var daten = Mysql->getCustomerData(id);
var customer = new Customer(daten);
// change some values
customer->setName('foo');
customer->setAdress('bar');
// save data
Mysql->setCustomerData(customer);
?

oder ehr so?
Code:
class Customer {
     Customer(id) {
         data = CustomerDB->get(data);
     }
}

habe ich so nicht am ende eine riesen Klasse mit hunderten methoden aufrufen? Oder meinst du man sollte 2 Klassen erstellen. Eine für die Daten verwaltung und ein für die DB Kommunikation, für jedes modul?

beim zweiten beispiel sehe ich den sinn nicht, denn auch wenn eine extra klasse, im programm ablauf ist der SQL aufruf ja dennoch innerhalb der Klasse.

Da scheint sich mir dann aber der wartungsaufwand zu vergrößern wenn ich immer 2 Klassen anpassen muss. Oder ich verstehe das einfach falsch.

die rechte verwaltung in die DB zu schieben erscheint mir hier aber def. zu aufwendig und kompliziert. Es ist eine multi DB architektur (die ist leider vorgegeben). Es gibt natürlich (schon wieder) mehrere Büros die verwaltet werden müssen und damit die Datenbanken sauber sind gibt es eine globale Datenbank welche Login und User Daten verwaltet und festlegt welcher user auch welche datenbank zugreifen kann. Dann gibt es datenbanken wie dhw_hamburg, dhw_frankfurt etc. (und ein ziemlich "dreckiges" tool um alle datenbanken gleichzeitig zu bearbeiten)
Ich habe zwar die autorisation das ggf. zu ändern, aber der aufwand....

aktuell ist die rechtverwaltung halt jeder user darf alles, jedes büro kann auf die datenbanken eines anderen büros zugreifen usw.
Es passieren auch ständig fehler weil die Mitarbeiter alles ändern können was sie wollen und wenn sie etwas nicht dürfen ist da nur ein roter kasten im Interface das sinngemäß sagt: "Du nicht ändern, das böse!"
 
Zuletzt bearbeitet:
Was ich meine ist eine DB-Klasse, die Funktionen hat wie DB-Connection prüfen/öffnen/schliessen und
diverse Funktionen die Dir die Daten zurückliefern. Diese sollten als Parameter z.B. den SQL haben sowie die Benutzercredentials.
Z.B. gibts dann eine Funktion Get_DataTable (sql,user_cred), Get_DataView... etc.
Die würdest Du dann in deinen Klassen aufrufen also in der Customer z.B.
data = Get_DataView ("Select customer_id where user='xyz'",curuser).

Achtung, schlechtes Beispiel, immer parametrisierte Abfragen Benutzen und auf Injections prüfen, geht hier nur ums Prinzip ;)
Und meine PHP-Zeiten sind schon etwas länger hinter mir.

Somit hättest Du eine saubere Trennung von DB-Funktionen und Deinen Klassenfunktionen selbst.

die rechte verwaltung in die DB zu schieben erscheint mir hier aber def. zu aufwendig und kompliziert. Es ist eine multi DB architektur (die ist leider vorgegeben)
Das macht man normal auch mit Rollen und nicht per User (wenn man sowas hat).
Oder Du legst je nachdem wieviel Rechte Konfigurationen Du hast einfach pro Rechtekonstellation einen User an.
Nichts desto trotz solltest Du das über Views regeln wenn Du feste Abfragen hast, im Quellcode einfach Felder herausnehmen ist
nicht wirklich eine Rechteverwaltung ;)
 
um mich gegen injections zu schützen leite ich ja gerade von mysqli ab um mit prepared statements arbeiten zu können ;) die klasse kümmert sich halt um das connecten etc. und stellt methoden bereit um mit der Datenbank zu kommunizieren.

die rechteverwaltung ist auch (zumindest php seitig) mit rollen gelöst. defacto wird es auch nicht viele rollen geben. ehr sowas wie disponent, logistiker, buchhaltung und admin (glaube tatsächlich das sind schon alle).
Disponenten haben sich aber nicht für Preise etc zu interessieren, logistiker müssen nur wissen wie viel von etwas da ist und wo es liegt usw.

ich kapiere das mit den views und credentials noch nicht so ganz. in den credentials steht dann drinne user darf feld A,B und C sehen/bearbeiten und D,E,F sind gesperrt?

Meinst du damit echte views auf der Datenbank? Oder das PHP das "view erzeugt" weil in dem "SQL" steht welche felder geladen werden?
In dem Fall müsste ich der Klasse ja beibringen was sie zu tun hat wenn ein Feld leer zurückkommt. Da die datenbank hoch normalisiert wurde gibt es selten Fälle in denen ich mal ein Feld nicht brauche, wenn dann wird eine ganze relation weggelassen.
Aber bsp. die buchhaltung muss sehen wie bestimmte Preise sind, darf diese aber auf keinen Fall ändern. Und wenn ein Monat abgeschlossen ist darf ohnehin niemand mehr etwas ändern (obwohl es hier ein schlupfloch geben muss um ggf. fehler zu korregieren), aber die daten weiterhin einsehen.
 
Die Views in der DB erzeugen per Create View und die Rechte der Spalten der verschiedenen Rollen hinterlegen. Auf die greifst Du dann zu wie wenn es eine Tabelle wäre. In den Credentials steht normalerweise User/Passwort je nachdem wie Du Deinen DB-Connect aufbaust brauchst Du die pro SQL oder auch nicht. Wenn z.b. immer nur 1 DB Connection per Singleton für alle User offen ist musst Du das pro SQL machen, wenn jeder User eine eigene DB Connection bekommt reichts dort den User/Rolle zu setzen.

Edit: Was Deine Monatsproblrmatik betrifft müsstest Du entweder tatsächlich programmieren oder den aktuellen Monat in einer bearbeitbaren Extra-Tabelle halten und per Cronjob am Ende des Monats rüberkopieren in eine Gesamttabelle auf die alle ausser Admins z.b. nur Leserechte haben. Oder über Trigger abfangen sofern möglich, macht die DB aber langsam
 
Zuletzt bearbeitet:
Zurück
Oben