it-swarm.com.de

Wo und von wem sollen Benutzerberechtigungsprüfungen in und MVC stattfinden?

Sollten Benutzerberechtigungsprüfungen im Modell oder in der Steuerung stattfinden? Und wer sollte die Berechtigungsprüfungen, das Benutzerobjekt oder einen UserManagement-Helfer durchführen?

Wo soll es passieren?

Einchecken des Controllers:

class MyController {
  void performSomeAction() {
    if (user.hasRightPermissions()) {
      model.someAction();
    }
  }
  ...

Die Überprüfungen im Controller helfen dabei, die Modelle zu einfachen Aktionen zu machen, sodass wir die gesamte Logik für die Controller behalten können.

Einchecken des Modells:

class MyModel {
  void someAction() {
    if (user.hasRightPermissions()) {
      ...
    }
  }
  ...

Indem wir die Überprüfungen in das Modell einfügen, erschweren wir das Modell, stellen aber auch sicher, dass Benutzer nicht versehentlich Dinge tun dürfen, die sie im Controller nicht tun sollen.

Und von wem?

Wer sollte die Kontrollen durchführen, sobald wir uns für den Ort entschieden haben? Der Nutzer?

Class User {
  bool hasPermissions(int permissionMask) {
    ...
  }
  ...

Aber es liegt nicht wirklich in der Verantwortung des Benutzers, zu wissen, auf was er oder sie zugreifen kann, also vielleicht eine Helferklasse?

Class UserManagement {
  bool hasPermissions(User user, int permissionMask) {
    ...
  }
  ...

Ich weiß, dass es üblich ist, nur eine einzige Frage in einer Frage zu stellen, aber ich denke, diese können gut zusammen beantwortet werden.

27
kba

Wie immer "kommt es darauf an"

  • berechtigungsprüfungen funktionieren funktionell überall dort, wo es bequem ist, sie zu platzieren.
  • wenn Sie jedoch eine technische Frage stellen, lautet die Antwort möglicherweise "Setzen Sie die Prüfungen in das Objekt ein, das die für die Durchführung der Prüfung erforderlichen Daten besitzt" (wahrscheinlich der Controller).
  • wenn Sie jedoch eine philosophische Frage stellen, schlage ich eine alternative Antwort vor: Zeigen Sie den Benutzern keine Aktionen an, die sie nicht ausführen dürfen.

Im letzteren Fall können Sie die Berechtigungsprüfung im Controller als boolesche Eigenschaft implementieren lassen und diese Eigenschaft an die Visible-Eigenschaft der Schaltfläche oder des Bedienfelds in der Benutzeroberfläche binden, die die Aktion steuert

als Benutzer ist es frustrierend, Schaltflächen für Aktionen zu sehen, die ich nicht ausführen kann. fühlt sich an, als würde ich vom Spaß ausgeschlossen;)

21
Steven A. Lowe

Sicherheit ist ein Querschnittsthema und muss daher in mehreren Ebenen implementiert werden. Was folgt, ist ein Beispiel für MVC, aber das Konzept gilt für andere Architekturen und/oder Muster. Sie müssen nur die Durchsetzungspunkte identifizieren.

Wo soll es passieren?

Ansichten können UI-Elemente (Widgets, Schaltflächen, Menüs usw.) enthalten, die je nach Berechtigung für einige Benutzer angezeigt werden müssen oder nicht. Dies könnte in der Verantwortung der View Engine liegen, da nicht jede Ansicht dies alleine behandeln soll. Abhängig von der Art der Elemente, für die Sie eine Autorisierung durchführen, verschieben Sie diese Verantwortung an einen anderen Ort. Stellen Sie sich zum Beispiel ein Menü vor, in dem einige Elemente angezeigt werden müssen und andere nicht. Die Elemente können irgendwo als Liste implementiert werden und diese Liste basierend auf Berechtigungen filtern und dann an die Ansicht weiterleiten.

Controller reagieren auf Anforderungen. Wenn ein Benutzer nicht über die Berechtigung zum Ausführen einer Aktion verfügt, sollte diese vor dem Aufrufen der Aktion überprüft werden, wodurch die Verantwortung verschoben wird an den Aktionsaufrufer anstatt ihn im Controller zu behalten. Dies hat den Vorteil, dass Ihr Controller sauber bleibt. Wenn sich die Berechtigungen ändern, müssen Sie Ihre Controller nicht durchsuchen, um diese Änderungen zu übernehmen.

Ressourcen werden basierend auf Berechtigungen angezeigt. Dies erfolgt normalerweise auf der Ebene Datenbank, da Sie nicht alles aus der Datenbank abrufen und dann Berechtigungen anwenden möchten.

Wie Sie sehen, gibt es je nachdem, was Sie autorisieren möchten, verschiedene Stellen, an denen dies durchgeführt werden sollte. Das Ziel ist es, so unauffällig wie möglich zu sein, damit Sie Ihre Sicherheitsrichtlinie bei Änderungen problemlos anwenden können, vorzugsweise ohne den Code Ihrer Anwendung zu ändern. Dies gilt möglicherweise nicht für kleine Anwendungen, bei denen der Berechtigungssatz relativ klein ist und sich nicht sehr oft ändert. In Unternehmensanwendungen sieht die Geschichte jedoch ganz anders aus.

Wer sollte das tun?

Ganz klar nicht das Modell. Jede Schicht sollte einen Durchsetzungspunkt haben, der die Autorisierung verwaltet. Der kursive Text oben hebt den möglichen Durchsetzungspunkt für jede Ebene hervor.

Schauen Sie sich XACML an. Sie müssen es nicht so implementieren, wie es ist, aber es gibt Ihnen einige Anweisungen, denen Sie folgen können.

7
devnull

Ich benutze folgendes Schema. Es ist anzumerken, dass die meisten Benutzerberechtigungsprüfungen in zwei allgemeine Fälle unterteilt werden können:

  • benutzerzugriff auf Controller-Aktion basierend auf Benutzerrolle ohne Überprüfung der Parameter Aktion wird aufgerufen mit,
  • benutzerzugriff auf das Modell basierend auf einer Logik oder Beziehung zwischen einem bestimmten Benutzer und einem bestimmten Modell.

Der Zugriff auf Controller-Aktionen ohne Überprüfung der Attribute wird normalerweise in MVC-Frameworks implementiert. Das ist überhaupt einfach: Sie definieren Regeln, Ihre Benutzer haben eine Rolle. Sie überprüfen einfach, ob der Benutzer die Berechtigung hat, seine Rolle in Regeln nachzuschlagen.

Der Benutzerzugriff auf ein bestimmtes Modell sollte im Modell definiert werden. (Der Schauspieler ist eine Basisbenutzerklasse. Angenommen, es kann sich entweder um einen Kunden, einen Verkäufer oder einen Gast handeln.)

interface ICheckAccess
{
    public function checkAccess(Actor $actor, $role);
}

class SomeModel implements ICheckAccess
{
    public function checkAccess(Actor $actor, $role)
    {
        // Your permissions logic can be as sophisticated as you want.
    }
}

Das Einfügen dieser Logik in das Modell bringt einen gewissen Gewinn. Die Zugriffsprüfungsmethode kann vererbt werden. Sie müssen keine zusätzlichen Klassen erstellen. Sie können allgemeine OOP Vorteile) verwenden.

Als nächstes vereinfachen wir zur Vereinfachung der Zugriffsprüfung einige Annahmen, die der Einfachheit und dem guten Stil nach fast immer bereits implementiert sind:

  • normalerweise beziehen sich Steuerungen auf eine Modellklasse.
  • aktionen, die auf Zugriff geprüft werden, verwenden eine einzelne Modell-ID als Parameter.
  • auf diesen Parameter kann immer einheitlich über die Methode der Basis-Controller-Klasse zugegriffen werden.
  • die Aktion wird in der Steuerung platziert, die dem Modell entspricht, für das die ID-Aktion ausgeführt wird.

Mit diesen Annahmen können Aktionen, die die Modell-ID verwenden, einer bestimmten Modellinstanz zugeordnet werden. Tatsächlich können die meisten Aktionen leicht transformiert und verschoben werden, um den oben genannten Annahmen zu entsprechen.

Dann sollte eine abstrakte Basis-Controller-Klasse definiert und vererbt werden.

abstract class ModelController
{
    // Retrieve model from database using id from action parameter.
    public abstract function loadModel($id);

    // Returns rules for user role to pass to SomeModel::checkAccess()
    // Something like array('view' => 'viewer', 'delete' => 'owner', 'update' => 'owner')
    public abstract function modelRules();

    public abstract fucntion getIdParameter();

    public function filterModelAccess()
    {
        $id = $this->getIdParameter();
        if(!$this->checkModelAccess($id))
            throw new HttpException(403);
    }

    public function checkModelAccess($id)
    {
        $model = $this->loadModel($id);
        $actor = My::app()->getActor();
        $rules = $this->modelRules();
        $role = $rules[My::app()->getActionName()];
        return $model->chechAccess($actor, $role);
    }
}

Sie können die SomeController :: checkModelAccess-Methode ($ id) aufrufen, wenn Sie Ihre Menüs erstellen und entscheiden, ob ein Link angezeigt werden soll.

1
George Sovetov

Sowohl in der Modellansicht als auch in der Ansicht

In der Ansicht - weil die Benutzeroberfläche nicht die Benutzeroberflächenelemente anzeigen sollte, die auf den aktuellen Benutzer beschränkt sind

(wie zum Beispiel sollte die Schaltfläche "Löschen" Personen mit entsprechenden Berechtigungen angezeigt werden)

Im Modell - weil Ihre App wahrscheinlich eine Art API hat, oder? Die API muss auch die Berechtigungen überprüfen und verwendet das Modell wahrscheinlich wieder.

(Zum Beispiel haben Sie die Schaltfläche "Löschen" in der Benutzeroberfläche nd die API-Methode "http:/server/API/DeleteEntry/123" gleichzeitig

1
jitbit

MVC ist ein Präsentationsmuster. Daher sollten Ansicht und Controller nur für die Präsentation verantwortlich sein. Einige Berechtigungen gelten für die Präsentation, z. B. ein Expertenmodus, experimentelle Benutzeroberflächenfunktionen oder verschiedene Designs. Diese können vom MVC-Controller verwaltet werden.

Viele andere Arten von Berechtigungen sind auf mehreren Ebenen der Anwendung relevant. Wenn Sie beispielsweise Benutzer haben möchten, die nur Daten anzeigen und keine Änderungen vornehmen können:

  • die Präsentationsebene muss die Bearbeitungsfunktionen ausblenden
  • Wenn eine Bearbeitungsfunktion trotzdem aufgerufen wird, könnte/sollte dies erkannt werden (von den anwendungsspezifischen Teilen der Geschäftsschicht, nicht vom domänenspezifischen Teil davon - TrainEditor, nicht Train) und wahrscheinlich eine Ausnahme verursachen
  • Die Datenzugriffsschicht kann auch nach Schreibvorgängen suchen, jedoch nach komplexeren Arten von Berechtigungen, die schnell zu viel Wissen über die Geschäftsschicht erfordern, um eine gute Idee zu sein.

Dieser Ansatz weist einige Überschneidungen auf. Da die Präsentation normalerweise volatil ist, kann man die Berechtigung im normalerweise stabileren Teil der Anwendung überprüfen, auch wenn dies einige redundante Überprüfungen bedeutet, falls die Präsentationsschicht wie beabsichtigt funktioniert.

0
Patrick