Implementieren von DDD: Benutzer und Berechtigungen

16

Ich arbeite an einer kleinen Anwendung, um die Prinzipien des domänengetriebenen Designs zu verstehen. Bei Erfolg könnte dies ein Pilotprojekt für ein größeres Projekt sein. Ich versuche, dem Buch "Implementing Domain-Driven Design" (von Vaughn Vernon) zu folgen und ein ähnliches, einfaches Diskussionsforum zu implementieren. Ich habe mir auch die IDDD-Samples auf Github angesehen. Ich habe einige Schwierigkeiten, die Identität und den Zugang zu meinem Fall zu übernehmen. Lassen Sie mich einige Hintergrundinformationen geben:

  • Ich verstehe (hoffentlich) die Gründe für die Trennung von Benutzer- und Berechtigungslogik: Es ist eine unterstützende Domäne und es ist ein anderer begrenzter Kontext.
  • In der Kerndomäne gibt es keine Benutzer, nur Autoren, Moderatoren usw. Diese werden erstellt, indem mit einem Dienst auf den Identitäts- und Zugriffskontext zugegriffen und die empfangenen Benutzerobjekte in einen Moderator übersetzt werden.
  • Domain-Operationen werden mit einer verwandten Rolle als Parameter aufgerufen: zB:

    ModeratePost( ..., moderator);

  • Die Methode des Domänenobjekts überprüft, ob die angegebene Moderatorinstanz nicht null ist (die Moderatorinstanz ist null, wenn der vom Identitäts- und Zugriffskontext angeforderte Benutzer nicht die Moderatorrolle hat).

  • In einem Fall führt es eine zusätzliche Prüfung durch, bevor ein Beitrag geändert wird:

    if (forum.IsModeratedby(moderator))

Meine Fragen sind:

  • Im letzteren Fall werden die Sicherheitsbedenken nicht erneut in die Kerndomäne integriert. Bisher heißt es in den Büchern: "Wer kann ein Thema veröffentlichen oder unter welchen Bedingungen ist dies zulässig? Ein Forum muss nur wissen, dass ein Autor dies gerade tut."

  • Die rollenbasierte Implementierung in diesem Buch ist recht einfach: Wenn ein Moderator die Kerndomäne ist, versucht er, die aktuelle Benutzer-ID in eine Moderator-Instanz oder in einen Autor zu konvertieren, wenn dies erforderlich ist. Der Dienst antwortet mit der entsprechenden Instanz oder einer Null, wenn der Benutzer nicht über die erforderliche Rolle verfügt. Ich kann jedoch nicht erkennen, wie ich dies an ein komplexeres Sicherheitsmodell anpassen kann. Unser aktuelles Pilotprojekt hat ein recht komplexes Modell mit Gruppen, ACLs usw.

Sogar mit Regeln, die nicht sehr komplex sind, wie: "Ein Beitrag sollte nur von seinem Besitzer oder einem Redakteur bearbeitet werden", scheint dieser Ansatz zusammenzubrechen, oder zumindest sehe ich nicht die richtige Art, ihn umzusetzen.

Wenn ich den Identitäts- und Zugriffskontext nach einer OwnerOrEditor-Instanz frage, fühle ich mich nicht richtig, und ich würde immer mehr sicherheitsrelevante Klassen in der Kerndomäne finden. Außerdem müsste ich nicht nur die Benutzer-ID, sondern auch den Bezeichner der geschützten Ressource (die ID des Posts, des Forums usw.) an den Sicherheitskontext übergeben, der sich wahrscheinlich nicht um diese Dinge kümmern sollte (stimmt das? )

Wenn Sie die Berechtigungen für die Kerndomäne abrufen und sie in den Methoden der Domänenobjekte oder in den Diensten überprüfen, gelangen Sie zum ersten Punkt: Mischen von Sicherheitsbedenken mit der Domäne.

Ich habe irgendwo gelesen (und bin damit einverstanden), dass diese berechtigungsbezogenen Dinge nicht Teil der Kerndomäne sein sollten, es sei denn, Sicherheit und Berechtigungen sind die Kerndomäne selbst. Rechtfertigt eine einfache Regel wie die oben angegebene, Sicherheit zu einem Teil der Kerndomäne zu machen?

LittlePilgrim
quelle
Vielleicht finden Sie hier das, was Sie brauchen: stackoverflow.com/a/23485141/329660 Nur weil der Zugriffskontrollkontext eine Ressourcen- ID kennt, bedeutet dies nicht, dass er über Domänenwissen darüber verfügt, welche Art von Entität diese Ressource ist oder was sie ist tut.
Guillaume31
Danke, ich habe diesen Beitrag bereits gesehen. Mein Problem ist genau das, was die Bearbeitung am Ende sagt: Ich möchte die Zugriffskontrolle aus meiner Kerndomäne entfernen, habe aber das Gefühl, mit meiner Implementierung gegen eine Wand gestoßen zu sein. Ihr Vorschlag zur Ressourcen-ID ist jedoch sinnvoll: Da ich in der Kerndomäne nicht das Konzept "Benutzer" oder "Rolle", sondern konkrete Rollen verwende, könnte ich möglicherweise das Konzept "Ressource" im Sicherheits-BC verwenden und diese auf den entsprechenden konkreten Fall abbilden Domain-Konzept. Einen Versuch wert, danke!
LittlePilgrim
Antworten die Codebeispiele im Link nicht zumindest auf "Ich kann nicht sehen, wie ich dies an ein komplexeres Sicherheitsmodell anpassen kann" ?
guillaume31
Mein Problem liegt nicht in der Implementierung des Sicherheitsmodells selbst. Ich kann nicht erkennen, wie ich diese komplizierteren Regeln der Domäne zuordnen soll. Wie sollte sich die Benutzer-> Autorenzuordnung ändern, wenn es sich auf der Sicherheitsseite nicht um ein einfaches rollenbasiertes Modell handelt? Das Übergeben von Ressourcen-IDs an den anderen Kontext funktioniert möglicherweise, HasPermissionToEdit(userId, resourceId)aber ich halte es nicht für richtig, die Domänenlogik mit diesen Aufrufen zu kontaminieren. Wahrscheinlich sollte ich diese in den Anwendungsdienstmethoden überprüfen, bevor ich die Domänenlogik aufrufe?
LittlePilgrim
Natürlich sollte es in Anwendungsdiensten sein ... Ich dachte, es sei aus Teilen des Codes klar, wie UserService @AccessControlList[inf3rno]in der Antwort, auf die ich verlinkt habe.
Guillaume31

Antworten:

6

Es ist manchmal schwierig, zwischen echten Zugriffssteuerungsregeln und Domäneninvarianten zu unterscheiden, die an die Zugriffssteuerung angrenzen.

Insbesondere Regeln, die von Daten abhängen, die nur bis weit in den Verlauf einer bestimmten Domänenlogik hinein verfügbar sind, können möglicherweise nicht einfach aus der Domäne extrahiert werden. In der Regel wird die Zugriffssteuerung vor oder nach einer Domänenoperation aufgerufen, jedoch nicht während.

Das assert (forum.IsModeratedBy(moderator))Beispiel von Vaughn Vernon hätte wahrscheinlich außerhalb der Domäne liegen sollen, aber es ist nicht immer machbar.

Ich müsste nicht nur die Benutzer-ID, sondern auch die Kennung der geschützten Ressource (die ID des Posts, des Forums usw.) an den Sicherheitskontext übergeben, der sich wahrscheinlich nicht um diese Dinge kümmern sollte (ist es korrekt?).

Wenn es einen Sicherheits-BC gibt und Sie möchten, dass er diese Logik handhabt, muss er nicht wissen, was ein Forum im Detail ist, sondern:

  • Es könnte nur Kenntnisse über Konzepte wie "moderiert von" haben und Zugriffsrechte entsprechend gewähren oder verweigern.
  • Möglicherweise ist eine Adapterlogik vorhanden, die Core Domain-Ereignisse abonniert und in einfache Schlüsselwertpaare (Ressourcen, berechtigte Benutzer) übersetzt, die vom Security BC gespeichert und verwendet werden können.
guillaume31
quelle
Da beide Antworten nützlich sind und mehr oder weniger in dieselbe Richtung weisen, habe ich beide positiv bewertet. Ich habe diese akzeptiert, da @ guillaume31 meine Frage zur Implementierung von Vernon mehr oder weniger beantwortet hat und ich mit meiner Implementierung fortfahren werde, basierend auf seinem Hinweis zur Verwendung von Ressourcen im Sicherheits-BC.
LittlePilgrim
Ich muss sagen, dass ich das im Gegenteil zu meiner Antwort finde.
Ewan
1
Vielleicht bin ich jetzt zu verwirrt, aber meine Interpretation war (für beide Antworten): 1. Halten Sie Sicherheitsbedenken von der Domäne fern und verwenden Sie den Sicherheits-BC als Dienst 2. Rufen Sie den Dienst auf, bevor Sie Domänenobjekte aufrufen 3. Der Dienst führt die Zuordnung von Benutzern / ACLs zu Moderatoren, Autoren usw. durch. moderator = securityService.GetModerator(userId, forumId) 4. Die Domänenlogik wird in diesen Objekten wie in moderator.EditPost () implementiert. 5. Methoden wie EditPost wissen nichts über Sicherheitskonzepte, es werden keine zusätzlichen Prüfungen durchgeführt dort
LittlePilgrim
Ich bin immer noch auf der Suche nach Antworten / Anweisungen, aber ich habe festgestellt, dass jede Berechtigungslogik, die sich auf den aktuellen Status des Objekts stützt (z. B. wenn es derzeit einem Moderator zugewiesen ist), tatsächlich eine Geschäftslogik ist, die zu gehört Ihre Domain und außerdem besteht die Gefahr, dass Sie in einem ungültigen Status enden, wenn das Modell gleichzeitig aktualisiert werden kann, wenn es sich nicht in Ihrer Domain befindet. Wenn Sie beispielsweise den Besitz mithilfe einer Richtlinie validieren und dann dieses Objekt aktualisieren, kann sich in vielen Domänen der Besitz ändern und die Aktion ist möglicherweise nicht mehr gültig.
Jordan
Sofern Sie keinen sehr komplexen kollaborativen Kontext haben, können Sie es sich wahrscheinlich leisten, hier ein optimistisches Parallelitätsmodell mithilfe der Versionierung zu implementieren. Wenn Ihre Überprüfungen jedoch nicht innerhalb einer bestimmten Gesamtinstanz oder zumindest mit einer bestimmten Gesamtinstanz durchgeführt werden, stimmen Ihre Überprüfungen möglicherweise nicht mit den tatsächlichen überein Zustand des Objekts, bis Sie Ihre Änderungen beibehalten.
Jordan
5

Authentifizierung und Autorisierung ist ein schlechtes Beispiel für DDD.

Keines dieser Dinge ist Teil einer Domain, es sei denn, Ihr Unternehmen erstellt Sicherheitsprodukte.

Die Geschäfts- oder Domänenanforderung lautet oder sollte "Ich benötige rollenbasierte Authentifizierung".

Anschließend überprüfen Sie die Rolle, bevor Sie eine Domänenfunktion aufrufen.

Wenn Sie komplexe Anforderungen haben, z. B. "Ich kann meine eigenen Beiträge bearbeiten, aber keine anderen", stellen Sie sicher, dass Ihre Domain die Bearbeitungsfunktion aufteilt EditOwnPost()und EditOthersPost()Sie eine einfache Funktion für die Rollenzuordnung haben

Sie können die Funktionalität auch in Domänenobjekte unterteilen, z. B. Poster.EditPost()und Moderator.EditPost()dies ist ein eher OOP-Ansatz, obwohl Ihre Wahl möglicherweise davon abhängt, ob sich Ihre Methode in einem Domänendienst oder in einem Domänenobjekt befindet.

Sie können den Code jedoch so trennen, dass die Rollenzuordnung außerhalb der Domäne erfolgt. Wenn Sie beispielsweise einen Webapi-Controller haben:

PostController : ApiController
{
    [Authorize(Roles = "User")]
    public void EditOwnPost(string postId, string newContent)
    {
        this.postDomainService.EditOwnPost(postId, string newContent);
    }

    [Authorize(Roles = "Moderator")]
    public void EditOtherPost(string postId, string newContent)
    {
        this.postDomainService.EditOtherPost(postId, string newContent);
    }
}

Wie Sie sehen, ist die komplexe Logik der Bearbeitung Ihres eigenen oder eines anderen Posts Teil der Domäne, obwohl die Rollenzuordnung auf der Hostebene erfolgt .

Die Domäne erkennt den Unterschied der Aktionen, aber die Sicherheitsanforderung besteht einfach darin, dass "die Funktionalität durch Rollen eingeschränkt werden kann" .

Dies ist vielleicht mit der Trennung der Domänenobjekte klarer, aber im Wesentlichen überprüfen Sie die Methode, die das Objekt erstellt, anstelle der Methode, die die Dienstmethode aufruft. Ihre Anforderung, wenn Sie sie dennoch als Teil der Domäne äußern möchten, würde lauten: "Nur Moderatoren können das Moderatorobjekt erstellen."

Ewan
quelle
4
Das Überprüfen der Rolle "statisch" ist ein bisschen simpel. Was ist, wenn ein Moderator den Beitrag eines anderen Moderators nicht bearbeiten darf? Sollte dieser Check nicht Teil der Domain sein?
Réda Housni Alaoui
2
@ RédaHousniAlaoui Ich frage mich auch darüber. Ich kann mir keine andere Möglichkeit vorstellen, um damit umzugehen, als entweder Benutzer / Moderatoren in der Domäne zu erwähnen oder eine Art Logik in diesem ApiController auszuführen, um die Rolle des Autors des Posts zu ermitteln. Keines von beiden scheint richtig zu sein, und dies ist meiner Erfahrung nach so verbreitet, dass eine klare Anleitung äußerst hilfreich wäre.
Jimmy
1
@Erwan, der Anwendungsfall, von dem ich spreche, ist dynamisch. Den Satz "Authentifizierung und Autorisierung ist ein schlechtes Beispiel für DDD" auf hallo Weltbeispiele zu stützen, ist unehrlich. DDD soll die versehentliche Komplexität vermeiden und die Verwaltung der Domänenkomplexität ermöglichen. Dynamische Berechtigungen sind weder eine zufällige Komplexität noch etwas, das im wirklichen Leben nicht vorkommt.
Réda Housni Alaoui
1
IMHO ist das Problem mit Ihrer Lösung, dass es den Kunden nicht zufrieden stellt. Der Kunde möchte diese Beziehungen häufig dynamisch ändern können. Dies ist auch der Fall, wenn ein Anbieter die gleiche Unternehmenssoftware für verschiedene Unternehmen bereitstellt. Wenn die Software schlecht optimiert werden kann, stirbt der Hersteller schließlich.
Réda Housni Alaoui
1
"Aber es wird allgemein als" schlecht "eingestuft, dass Ihre Sicherheitseinstellungen im Laufe der Zeit nicht mehr verwaltet werden können, was effektiv bedeutet, dass Ihre App unsicher wird." Mit dem richtigen Design und Test ist es völlig handlich. Unter Windows XP muss die Domäne jedoch die Berechtigung überprüfen, um das richtige Design zu erstellen. Die Alternative ist Utopie.
Réda Housni Alaoui