Laden...

Rechtesystem wo anwenden? GUI oder BLL?

Erstellt von serial vor 13 Jahren Letzter Beitrag vor 13 Jahren 4.006 Views
S
serial Themenstarter:in
902 Beiträge seit 2007
vor 13 Jahren
Rechtesystem wo anwenden? GUI oder BLL?

Hallo,

ich bin gerade dabei, ein Rechtesystem zu entwickeln, und da bin ich schon auf eine Frage gestoßen...die mir etwas kopfzerbrechen bereitet.
Wo sollte eine Prüfung der Rechte stattfinden?

Beim Aufruf der Methoden für einen bestimmten use-case?
Beim Aufbau der Benutzeroberfläche?

Als Beispiel, das Speichern eines Artikels.

Diesen Use-Case habe ich in meiner BLL-Fasade als Methode (SaveArticle), sollte nun meine BL-Komponente eine vorgeschaltete Rechteüberprüfungs-Komponente haben, nach dem Motto: "Darf der User die Methode aufrufen, oder soll ich ne Exception werfen?", oder soll das View dieses Recht abprüfen, und zB den Speichern-Button ausgrauen, bzw das View garnicht erst anzeigen?

Nachteil der GUI-Sache ist, das ich überall diese Überprüfung neu einbauen müsste, wenn die BL-Komponente woanders verwendet wird.

hat da jemand eine Meinung dazu?

mfg
serial

2.298 Beiträge seit 2010
vor 13 Jahren

Wir handhaben das im Unternehmen so, dass wir boolsche Felder im Code der Oberfläche nutzen um festzustellen welche Rechte der Benutzer hat.

Dafür haben wir eine Webservice gestützte Authentifizierung die die Rechte zurück liefert.

Nach Anmeldung des Nutzers werden die jeweiligen Felder dann auf true beziehungsweise false gesetzt und Buttons sowie Menüpunkte die der Nutzer nutzen darf aktiviert.

Nach dem Logout werden die private fields zurück gesetzt und die Menüpunkte und Buttons wieder deaktiviert.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 13 Jahren

Also die BLL wird nicht direkt durch das system geschützt?

mfg
serial

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo serial,

Nachteil der GUI-Sache ist, das ich überall diese Überprüfung neu einbauen müsste, wenn die BL-Komponente woanders verwendet wird.

genau deshalb sollten die Prüfungen in BL erfolgen. Wenn man die Prüfungen allerdings in den Methoden des BLs hardcodiert, hat man das Problem, dass das GUI erst dann mitbekommt, dass eine Regel verletzt wurde, nachdem die entsprechende Methode oder Property aufgerufen wurde. Oft möchte man aber schon im GUI Regelverletzungen verhindern, z.B. in dem man bestimmte Felder oder Buttons disabled. Also brächte auch das GUI die Information über die Regeln. Deshalb bietet es sich an, die Regeln nicht in den Methoden und Settern zu codieren, sondern z.B. als deren Attribute, also so wie ich das in [Artikel] Attribute zur Prüfung von Properties verwenden vorgeschlagen habe.

herbivore

3.728 Beiträge seit 2005
vor 13 Jahren
Beides

Hallo serial,

in beiden Stellen muss abgesichert werden. Wenn ich nur die BLL-Funktionen absichere, dann merkt der Benutzer erst dann, dass er nicht berechtigt ist, wenn er schon auf den Button gedrückt hat. Er soll den Button aber eigentlich gar nicht erst sehen.

Ideal finde ich deshalb ein System, welches BLL-Funktionen und Oberflächenelemente gleichermaßen absichert. Und das mit einer gemeinsamen Datenbasis. Wenn ein bestimmter Knopf eine bestimmte BLL-Funktion aufruft, dann kann ich dem Knopf ja den selben Rechteschlüssel zuordnen, wie der Funktion.

So eine "Funktionsbasierte Rechteprüfung" haben die meisten Anwendungen. Was oft fehlt, ist eine "Datenbezogene Rechteprüfung". Eine die z.B. die Frage beantworten kann, ob Benutzer Mustermann Datensatz 4711 sehen darf, oder nicht.

Berechtigungen sollten immer irgendwo außerhalb des Codes gespeichert werden (z.B. in einer Datenbank).

J
1.114 Beiträge seit 2007
vor 13 Jahren

Die Überprüfung MUSS imho im BL stattfinden. Wenn der Check lediglich im Gui gemacht wird, kann man trotzdem, z.B. über eine eigene Gui, die Funktionen im BL aufrufen. Wenn ich also verhindern will, dass jemand die Methode SaveArticle() aus dem BL aufruft, dann muss das auch in dieser Methode geprüft werden.

Und richtige Sicherheit erzielt man so, wenn BL und Gui physikalisch getrennt sind, und sich der BL in einer Middleware befindet. In dem Fall hat der Anwender null Chancen, trotzdem an die SaveArticle() Methode zu gelangen.

Und die Überprüfung SOLL ebenfalls, aus Benutzerfreundlichkeit, im Gui stattfinden, um eben direkt entsprechente Gui Element zu disablen oder auszublenden.

Ich nutze hier ein eigenes UserManagment, das ich immer in all mein BL nutze, die ich wiederrum in einer Middleware hoste, und meine Clients über WCF anbinde.

Im BL gibt es dann eine Methode EnsurePolicy(string name). Die überprüft, ob der Client Rechte hat, und schmeisst eine Exception wenn dies nicht der Fall ist. In jedem OperationContract meines WCF steht dann in der ersten Zeile ein Aufruf von EnsurePolicy().

Weiter biete im Contract die Methode CheckPolicy(string name) an, über die der Client GUI-seitig prüfen kann, ob er das Recht besitzt, eine Methode im BL aufzurufen oder nicht.

CheckPolicy wird im BL durch ein CheckPolicy in meinem Usermanagement System durchgeführt.

Mit dieser Logik habe ich eigentlich bislang ganz gute Erfahrungen gemacht. Ein geeignetes Usermanagement System ist dafür natürlich auch Vorraussetzung.

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 13 Jahren

Hallo,

ok, dass ich beide stellen absichern muss, ist also relativ klar!
UInklar ist mir noch der fall, ob ich Use-Cases sichere, oder wirklich einzelne methoden?
Meine BLL stellt nicht für jeden Use-Case eine eigene Methode bereit, sondern manche verlangen den aufruf mehrerer Methoden. Wäre es hier günstig, eine schicht über meine BusinessComponenten zu legen, die wirklich USeCase - spezifische Methoden anbietet, und ich diese per Rechtemanagement absichere?

mfg
serial

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo serial,

Wäre es hier günstig, eine schicht über meine BusinessComponenten zu legen, die wirklich USeCase - spezifische Methoden anbietet, und ich diese per Rechtemanagement absichere?

dann müssten deine BusinessComponenten für das GUI und auch für alle anderen Stellen außer der UseCase-Schicht unsichtbar sein. Ein direkter Zugriff auf BusinessComponenten wäre dann nicht mehr möglich. Alle Zugriffe müssten und könnten nur noch über die UseCase-Schicht erfolgen. Wenn du damit leben kannst, kannst du das so machen. Mir kommt das aber auf den ersten Blick recht unflexibel und fehleranfällig vor.

Mir scheint es sinnvoller, das usecase-basierte Rechtesystem auf ein (elementar-)operationen-basiertes Rechtesystem herunterzubrechen, z.B. über eine Tabelle, in der steht, welche Methoden dem Benutzer erlaubt sind, wenn ihm ein bestimmter UseCase erlaubt ist. Das ist zwar auch nicht ohne Probleme, aber m.E. trotzdem der bessere Weg.

herbivore

J
1.114 Beiträge seit 2007
vor 13 Jahren

Ich sehe das genauso wie Herbivore. Halte dir die Flexibilität, gerade bei so Systemen die später in unterschiedlichen Anwendungen zum Einsatz kommen werden.

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 13 Jahren

Hallo nochmal,

also mir sind die Ansätze alle klar und verständlich!
Mein Problem liegt wohl eher in der implementierten Zuordnung der Rechte.

Beispiel UseCase "Rechnung erstellen":

Nehmen wir an, der besteht aus 2 Schritten, einmal einen Artikelstand aktualisieren, und einmal ein Rechungsobjekt speichern.

In der BLL gibt es eben diese beiden Methoden: UpdateArticleCount, und einmal SaveInvoice. In der GUI gibt es einen Button "erstelle Rechnung". Dies bedeutet, im Clickhandler werden im einfachsten Fall diese beiden Methoden in einer Transaktion ausgeführt. Mir ist nicht klar, wie ich hier ein sinnvolles Rechtesystem dazwischen schalte bzw implementiere.

Problem #1: wie bilde ich ein Recht auf eine Methode wie SaveInvoice ab? Als string den Methodenname in der DB? Über Attribute welche ausgelesen werden? Also wie kommt die Verbindung zwischen Recht aus der db und entsprechende Aktion im Code zustande? Oder gibt es ein benanntes Recht, welches ich im Code selbstständig abfragen muss? Welches nicht direkt mit den Methoden in Verbindnug steht?

Beispiel


//MEthodenbasiert, irgendwie
RechteManager.HatRecht(Methodendelegate); // hier überprüft er das recht, und wenn er es hat, führt er methode aus, bedeutet, dass der Methodenname in der DB stehen muss

//oder ein frei schwebendes Recht
RechteManager.HatRech("IrgendeinRechtName",Methodendelegate); //hier ist das Recht nciht direkt mit einer Methode verbunden, bedeutet, dass ich unter einem recht unterschiedliche sachen ausführen könnte, die emthoden selbst nicht geschützt sind.

Problem #2: In dem oben genannten UseCase: wie kann ich sinnvoll abbilden, wenn der User die Methode UpdateArticleCount ausführen darf, aber nicht SaveInvoice?

vielleicht seh ich nur den wald vor lauter bäumen nicht!

Hoffe ihr könnt mir auf die Sprünge helfen 😦

mfg
serial

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo serial,

RechteManager.HatRecht ist schonmal ein gute Ansatz.

wie bilde ich ein Recht auf eine Methode wie SaveInvoice ab?

Am einfachsten wird es sein, die einzelnen Rechte als enum-Werte zu definieren. Die Rechte können, aber müssen nicht 1:1 mit Methoden(namen) übereinstimmen.

Als string den Methodenname in der DB?

Geht auch.

Über Attribute welche ausgelesen werden?

Das war mein Vorschlag.

Also wie kommt die Verbindung zwischen Recht aus der db und entsprechende Aktion im Code zustande?

Wenn du es über Attribute machst, zeigt ja mein schon genannter Artikel, wie du die Verbindung herstellst. Kurz gesagt über den Aufruf einer entsprechenden Prüfmethode

Oder gibt es ein benanntes Recht, welches ich im Code selbstständig abfragen muss?

Der Aufruf der Prüfmethode muss natürlich irgendwie in den (Source- oder spätestens den Object-)Code. Man kann den Aufruf also entweder manuell oder per PostSharp o.ä. einfügen.

Welches nicht direkt mit den Methoden in Verbindnug steht?

Irgendeine Verbindung muss es schon geben, auch wenn diese z.B. mittels PostSharp nur indirekt erfolgt.

In dem oben genannten UseCase: wie kann ich sinnvoll abbilden, wenn der User die Methode UpdateArticleCount ausführen darf, aber nicht SaveInvoice?

Wenn du die Rechte so nennst wie die Methoden, kannst du das doch machen.

Das einzige was du so nicht hinbekommst, ist dass der Benutzer zwar das Recht "Rechnung erstellen" hat, aber nicht das Recht, die SaveInvoice Methode alleine aufzurufen. Das bekommst du nur mit dem Wrapper hin.

herbivore

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 13 Jahren

Das einzige was du so nicht hinbekommst, ist dass der Benutzer zwar das Recht "Rechnung erstellen" hat, aber nicht das Recht, die SaveInvoice Methode alleine aufzurufen. Das bekommst du nur mit dem Wrapper hin.

Genau, dass ist mein Verständnisproblem: Rechnung erstellen ist der UseCase, zusammengesetzt aus mehreren BLL-Methoden.

Wenn er eine Methode von mehreren nicht darf, darf er ja den ganzen Usecase nicht ausführen! Problem wäre hier, den Button vorher schon zu disablen, wenn eine Methode in seinem Handler kein Recht besitzt. Die anderen schon.

Also ich würde mich wohl dahingehend entscheiden, die MEthodennamen in der DB zu speichern, so kann ich über Reflection automatisch den Namen abfragen, und für den User das Recht prüfen.

Ich könnte ja zusätzlich noch Rechte für Usecases erstellen, welche ich im GUI benutzen kann, welche ja letztendlich den Geschäftsfall anstoßen?!
Wäre das eine saubere Herangehensweise?

Quasi würde es wohl so aussehen:


btnMakeInvoide.Enabled = RechteManager.HatRecht("RechnugnErstellenUseCase");
btn.Click += (s,e)=>
 {
   try
  {
   RechteManager.HatRecht(Bll.UpdateArticleCount);
  RechteManager.HatRecht(Bll.SaveInvoice);  //diese Aufrufe vielleicht noch kapseln hinter einer fasade
  }
  catch(NotGrantedException ex) 
  {
   //Meldung, loggen, was auch immer
  }
 }


wäre das brauchbar?

mfg
serial

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo serial,

wie schon gesagt würde ich eher die Rechte auf UseCase-Ebene vergeben (oder auf Ebene abstrakter Highlevel-Operationen) und die dann durch eine Tabelle mit Implikationen auf die Ebene der einzelnen Methoden herunterbrechen, zum Beispiel:

"Rechnung erstellen" ==> UpdateArticleCount, SaveInvoice

aber nicht so wie du es geschrieben hast per Code, sondern als Tabelle, Dictionary o.ä.

Auf der Ebene darüber würde ich Rollen definieren. Zum Beispiel eine Rolle "Schadenssachbearbeiter", die dann mit bestimmten UseCase-Rechten ausgestattet sind, die dann mit bestimmte Methoden-Rechte implizieren. Dann braucht man den Benutzern nur noch Rollen zuzuordnen und sich nicht damit rumzuschlagen den Benutzern (einzeln) zuzuordnen, welche Methoden sie benutzen dürfen.

Wenn du die Ebene der UseCase-Rechten also nicht weglässt, kannst du diese im GUI verwenden, um die Buttons auszugrauen.

herbivore

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 13 Jahren

Hallo herbivore,

ich weiss was du meinst, kann mir aber noch nciht genua vorstellen, wie die implementierung aussehen soll! Vielleicht bin ich auch nur gerade nicht mehr fähig richtig zu denken.
Wo werden die Recht in deiner Weise abgefragt?

Vielleicht könntest du mir an meinem beispiel, die anwendung deiner idee kurz zeigen?

Tut mir leid wenn ich mich vielleicht grade etwas anstelle. 😦

mfg
serial

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo serial,

ich habe die Idee in meinem Artikel ja nun ziemlich genau ausgearbeitet. Damit solltest du eigentlich klarkommen.

herbivore