Frage

Ich erstelle in Rails eine Community-basierte Website für die Mitglieder einer realen Organisation.Ich versuche, mich an die Best Practices des RESTful-Designs zu halten, und das meiste davon halte ich mehr oder weniger an die Vorschriften.Das Problem, das mein Gehirn in ordentlichen RESTful-Kreisen laufen lässt, ist das der Autorisierung. Authentifizierung ist ein einfaches, seit langem gelöstes Problem mit weithin akzeptierten RESTful-Lösungen, aber die RESTful-Autorisierung scheint eine Art schwarze Kunst zu sein.Ich versuche, den Ansatz zu finden, der den allgemeinsten und flexibelsten Rahmen für die Steuerung des Zugriffs auf Ressourcen bietet und gleichzeitig so einfach wie möglich ist und gleichzeitig einer RESTful-Architektur entspricht.(Auch ein Pony.)

Überlegungen:

  1. Ich muss den Zugriff auf eine Vielzahl von Ressourcen steuern, z. B. Benutzer, Seiten, Beiträge usw.
  2. Die Autorisierung für eine bestimmte Ressource muss feiner gegliedert sein als einfaches CRUD.
  3. Ich möchte mir und anderen erlauben, die Autorisierungsregeln innerhalb der Anwendung zu bearbeiten.
  4. Autorisierungsregeln sollten von Prädikaten abhängen dürfen, wie zum Beispiel (konzeptionell) Besitzer (Benutzer, Ressource) oder Gesperrt (Thema).

Überlegung (2) beschäftigt mich am meisten.Es scheint eine Impedanzinkongruenz zwischen meiner Vorstellung von Berechtigungen und der RESTful-Konzeption von Aktionen zu geben.Nehmen Sie zum Beispiel Beiträge (wie in einem Message Board).REST schreibt die Existenz von vier Vorgängen für die Post-Ressource vor:Erstellen, Lesen, Aktualisieren und Löschen.Es ist einfach zu sagen, dass ein Benutzer in der Lage sein sollte, seine eigenen Beiträge zu aktualisieren, aber nur bestimmte Benutzer (oder Rollen oder Gruppen) dürfen sie sperren.Die herkömmliche Art und Weise, das Sperren darzustellen, liegt innerhalb des Status des Beitrags, aber das führt zu dem Eindruck, dass ein Benutzer unter den gleichen Bedingungen möglicherweise in der Lage ist, einen Beitrag zu aktualisieren, abhängig von den (völlig gültigen) Werten, die er bereitstellt.Mir scheint klar zu sein, dass es eigentlich zwei verschiedene Maßnahmen gibt, um den Zustand der Post zu ändern, und diese zu unter Druck zu setzen bedeutet lediglich, einen Verstoß gegen die RESTful-Prinzipien zu verschleiern.

(Ich sollte beachten, dass sich dieses Problem deutlich von dem Problem eines fehlgeschlagenen Updates unterscheidet ungültig oder inkonsistent Daten – eine Sperranforderung eines unprivilegierten Benutzers ist im Prinzip durchaus gültig, einfach nicht zulässig.)

Ist Zersetzung nicht ein anderes Wort für Fäulnis?

Dies kann durch Zerlegen des Beitrags behoben werden:Eine Sperre ist eine Unterressource eines bestimmten Beitrags, und zum Erstellen oder Zerstören kann man dann über separate Berechtigungen verfügen.Diese Lösung erinnert an REST, bringt jedoch sowohl theoretische als auch praktische Schwierigkeiten mit sich.Wenn ich Sperren ausklammere, was ist dann mit anderen Attributen?Angenommen, ich entscheide in einem Anfall von Laune, dass nur ein Mitglied des Administrators berechtigt sein sollte, den Titel des Beitrags zu ändern?Eine einfache Änderung der Autorisierung würde dann eine Umstrukturierung der Datenbank erfordern, um diese zu berücksichtigen!Das ist keine große Lösung.Um diese Art von Flexibilität im Rahmen einer Zerlegungsstrategie zu ermöglichen, müsste jedes Attribut eine Ressource sein.Das stellt ein kleines Dilemma dar.Meine implizite Annahme war, dass eine Ressource in der Datenbank als Tabelle dargestellt wird.Unter dieser Annahme bedeutet eine Ressource für jedes Attribut eine Tabelle für jedes Attribut.Dies ist offensichtlich nicht praktikabel.Die Beseitigung dieser Annahme führt jedoch zu einer Impedanzinkongruenz zwischen Tabellen und Ressourcen, die ihre eigene Büchse voller Würmer öffnen könnte.Die Verwendung dieses Ansatzes würde weitaus ausführlichere Überlegungen erfordern, als ich sie dargelegt habe.Zum einen erwarten Benutzer vernünftigerweise, dass sie mehrere Attribute gleichzeitig bearbeiten können.Wohin geht die Anfrage?Zur kleinsten Ressource, die alle Attribute enthält?Zu jeder einzelnen Ressource parallel?Zum Mond?

Einige dieser Dinge sind nicht wie die anderen ...

Angenommen, ich zerlege keine Attribute.Die Alternative scheint dann darin zu bestehen, für jede Ressource eine Reihe von Berechtigungen zu definieren.An diesem Punkt geht jedoch die Homogenität von REST verloren.Um Zugriffsregeln für eine Ressource zu definieren, muss das System über spezifische Kenntnisse über die Fähigkeiten dieser Ressource verfügen.Darüber hinaus ist es jetzt nicht mehr möglich, Berechtigungen generisch an untergeordnete Ressourcen weiterzugeben – selbst wenn eine untergeordnete Ressource über ein gleichnamiges Privileg verfügt, besteht keine inhärente semantische Verbindung zwischen den Privilegien.Das Definieren eines REST-ähnlichen Satzes von Standardprivilegien scheint mir das Schlimmste aus beiden Welten zu sein, sodass ich auf eine separate Berechtigungshierarchie für jeden Ressourcentyp angewiesen bin.

Nun, wir haben die Nase gemacht.Und der Hut.Aber es ist eine Ressource!

Ein Vorschlag, den ich gesehen habe, der einige der Nachteile des oben genannten Ansatzes abmildert, besteht darin, Berechtigungen als „Erstellen/Löschen am“ zu definieren Ressourcen und lesen/schreiben Attribute.Dieses System ist ein Kompromiss zwischen Attributen als Ressourcen und Privilegien pro Ressource:Es bleibt immer noch nur CRUD übrig, aber zum Zwecke der Autorisierung beziehen sich „Lesen“ und „Aktualisieren“ auf Attribute, die man sich als Pseudoressourcen vorstellen könnte.Dies bietet viele der praktischen Vorteile des Ansatzes „Attribute als Ressourcen“, obwohl die konzeptionelle Integrität in gewissem Maße beeinträchtigt ist.Berechtigungen könnten weiterhin von Ressource zu Ressource und von Ressource zu Pseudo-Ressource weitergegeben werden, jedoch niemals von einer Pseudo-Ressource.Ich habe die Auswirkungen dieser Strategie noch nicht vollständig untersucht, aber es scheint, als ob sie vielversprechend sein könnte.Mir kommt vor, dass ein solches System am besten als integraler Bestandteil des Modells funktionieren würde.Bei Rails könnte es sich zum Beispiel um eine Nachrüstung handeln ActiveRecord.Das erscheint mir ziemlich drastisch, aber die Autorisierung ist ein so grundlegendes Querschnittsthema, dass dies gerechtfertigt sein könnte.

Oh, und vergiss das Pony nicht

All dies ignoriert die Frage der prädiktiven Berechtigungen.Natürlich sollte ein Benutzer die Möglichkeit haben, seine eigenen Beiträge zu bearbeiten, nicht jedoch die anderer.Ebenso offensichtlich sollte die vom Administrator geschriebene Berechtigungstabelle keine separaten Datensätze für jeden Benutzer enthalten.Dies ist keine ungewöhnliche Anforderung – der Trick besteht darin, sie generisch zu gestalten.Ich denke, dass die gesamte Funktionalität, die ich benötige, allein durch die Herstellung erreicht werden könnte Regeln prädikativ, so dass schnell und unmittelbar über die Anwendbarkeit der Regel entschieden werden konnte.Eine Regel "allow User write Post where Author(User, Post)„würde übersetzen als“for all User, Post such that Author(User, Post), allow User write Post", Und "deny all write Post where Locked(Post)" Zu "for all Post such that Locked(Post), deny all write Post".(Es wäre großartig wenn alle derartigen Prädikate in Bezug auf einen Benutzer und eine Ressource ausgedrückt werden könnten.) Die konzeptionell resultierenden „endgültigen“ Regeln wären nicht prädikativ.Dies wirft die Frage auf, wie ein solches System implementiert werden kann.Die Prädikate sollten Mitglieder der Model-Klassen sein, aber ich bin mir nicht sicher, wie man im Kontext der Regeln elegant auf sie verweisen kann.Um dies sicher zu tun, wäre eine Art Reflexion erforderlich.Auch hier habe ich das Gefühl, dass dies eine Nachrüstung der Modellimplementierung erfordern würde.

Wie schreibt man das nochmal?

Die letzte Frage ist, wie diese Autorisierungsregeln am besten als Daten dargestellt werden können.Eine Datenbanktabelle könnte den Zweck erfüllen, mit Aufzählungsspalten für Zulassen/Verweigern und C/R/U/D (oder vielleicht CRUD-Bits?oder vielleicht {C, R, U, D} × {allow, deny, inherit}?) und eine Ressourcenspalte mit einem Pfad.Vielleicht, der Einfachheit halber, ein „Erben“-Bit.Was Prädikate angeht, bin ich ratlos.Separater Tisch?Sicherlich viel Caching, um dies zu verhindern zu gottlos langsam.


Ich denke, das ist eine Menge verlangt.Ich habe versucht, meine Hausaufgaben zu machen, bevor ich die Frage gestellt habe, aber an diesem Punkt brauche ich wirklich eine Außenperspektive.Ich würde mich über jeden Beitrag von Ihnen zu dem Problem freuen.

War es hilfreich?

Lösung

Es tut mir leid, dass ich keine Zeit habe, dieser Frage gerecht zu werden, aber es ist schön, einige gut durchdachte Fragen zu SO zu sehen.Hier einige Kommentare:

Tappen Sie nicht in die Falle, die HTTP-Verben CRUD zuzuordnen.Ja, GET und DELETE ordnen die Zuordnung ziemlich sauber zu, aber PUT kann Erstellen und Aktualisieren (aber nur vollständiges Ersetzen) und POST ist ein Platzhalterverb.Post ist wirklich alles, was nicht in Get, Setzen und Löschen passt.

Die Verwendung von Attributen zur Darstellung des Status eines Objekts ist nur ein Ansatz zur Statusverwaltung.Ich vermute, Sie können sich vorstellen, was die folgende Anfrage bewirken könnte:

POST /LockedPosts?url=/Post/2010

Eine Unterressource ist auch ein gültiger Ansatz zur Verwaltung des aktuellen Status einer Ressource.Ich würde mich nicht dazu verpflichtet fühlen, die „Zustands“-Attribute und „Daten“-Attribute einer Ressource einheitlich zu behandeln.

Der Versuch, Ressourcen direkt Tabellen zuzuordnen, wird Sie ernsthaft einschränken.Vergessen Sie nicht, dass Sie, wenn Sie die REST-Einschränkungen befolgen, plötzlich nur noch sehr begrenzte Verben zur Verfügung haben.Sie müssen in der Lage sein, dies durch Kreativität bei der Nutzung der Ressourcen auszugleichen.Wenn Sie sich auf eine Ressource beschränken, die einer Tabelle entspricht, wird die Funktionalität Ihrer Endanwendung erheblich eingeschränkt.

Wir sehen regelmäßig, dass Rails-, ASP.NET MVC- und WCF-Rest-Benutzer hier auf StackOverflow Fragen dazu stellen, wie bestimmte Dinge innerhalb der Einschränkungen von REST erledigt werden.Das Problem liegt oft nicht in einer Einschränkung von REST, sondern in den Einschränkungen des Frameworks bei der Unterstützung von RESTful-Anwendungen.Ich denke, es ist wichtig, zunächst eine RESTful-Lösung für ein Problem zu finden und dann zu prüfen, ob diese auf das Framework Ihrer Wahl zurückgeführt werden kann.

Soweit es darum geht, ein Berechtigungsmodell zu erstellen, das detaillierter ist als die Ressource selbst.Denken Sie daran, dass Hypermedia eine der wichtigsten REST-Einschränkungen ist.Hypermedia kann nicht nur zum Auffinden verwandter Entitäten verwendet werden, sondern kann auch zur Darstellung gültiger/erlaubter Zustandsübergänge verwendet werden.Wenn Sie eine Darstellung zurückgeben, die eingebettete Links enthält, abhängig von den Berechtigungen, können Sie steuern, welche Aktionen von wem ausgeführt werden können.d.h.Wenn ein Benutzer Berechtigungen zum Entsperren von POST 342 hat, können Sie den folgenden Link in die Darstellung eingebettet zurückgeben:

<Link href="/UnlockedPosts?url=/Post/342" method="POST"/>

Wenn sie nicht über diese Berechtigung verfügen, geben Sie den Link nicht zurück.

Ich denke, eine Ihrer Schwierigkeiten besteht hier darin, dass Sie versuchen, ein zu großes Problem auf einmal zu lösen.Ich denke, Sie müssen die RESTful-Schnittstelle, die Sie dem Client zur Verfügung stellen möchten, als ein anderes Problem betrachten als die Art und Weise, wie Sie die Berechtigungen und Prädikate verwalten, um die Autorisierung in Ihrem Domänenmodell zu verwalten.

Mir ist klar, dass ich keine Ihrer Fragen direkt beantwortet habe, aber ich hoffe, dass ich einige Standpunkte dargelegt habe, die in irgendeiner Weise hilfreich sein können.

Andere Tipps

Ich habe kürzlich eine Authentifizierungslösung entdeckt, die die meisten meiner Bedenken zu bewältigen scheint. Wenn Sie diese Frage beliebt haben, ist sie möglicherweise von Interesse für Sie:

https://github.com/stffn/declarative_authorization

Wie Darrel betonte, ist die Ruhe nicht Crud. Wenn Sie feststellen, dass Ihre identifizierten Ressourcen zu grobkörnig sind, dass die einheitliche Schnittstelle nicht genügend Kontrolle liefert, teilen Sie Ihre Ressource in Unter-Ressourcen auf und verwenden Sie die ursprüngliche Ressource als "Sammlung" von Hyperlinks in seine Komponenten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top