
Deklarative Autorisierungsbibliothek mit einer DSL zum Schreiben von Policy-Regeln, Bedingungen und Caching. Ermöglicht skalierbares, DRY-Berechtigungsmanagement für Ruby-Anwendungen.
DeclarativePolicy: Eine deklarative AutorisierungsbibliothekDiese Bibliothek bietet eine DSL zum Schreiben von Autorisierungsrichtlinien.
Sie kann verwendet werden, um Logik von Berechtigungen zu trennen, und wurde in großem Umfang in der Produktion bei GitLab.com eingesetzt.
Die ursprüngliche Autorin dieser Bibliothek ist Jeanine Adkisson, und das Urheberrecht liegt bei GitLab.
Fügen Sie diese Zeile zur Gemfile Ihrer Anwendung hinzu:
gem 'declarative_policy'
Und führen Sie dann Folgendes aus:
$ bundle install
Oder installieren Sie es selbst mit:
$ gem install declarative_policy
require 'declarative_policy'
class User
attr_reader :name
def initialize(name:)
@name = name
end
end
class Vehicle
def initialize(owner:, trusted: [])
@owner = owner
@trusted = trusted
end
def owner?(user)
@owner.name == user.name
end
def trusted?(user)
@owner.name == user.name || @trusted.detect { |t| t.name == user.name }
end
end
class VehiclePolicy < DeclarativePolicy::Base
condition(:owns) { @subject.owner?(@user) }
condition(:trusted) { @subject.trusted?(@user) }
rule { owns }.enable :sell_vehicle
rule { trusted }.enable :drive_vehicle
end
jack = User.new(name: 'jack')
jill = User.new(name: 'jill')
jacks_vehicle = Vehicle.new(owner: jack, trusted: [jill])
jills_vehicle = Vehicle.new(owner: jill, trusted: [jack])
puts "Jack can drive Jack's vehicle? -> #{DeclarativePolicy.policy_for(jack, jacks_vehicle).can?(:drive_vehicle)}"
puts "Jack can drive Jill's vehicle? -> #{DeclarativePolicy.policy_for(jack, jills_vehicle).can?(:drive_vehicle)}"
puts "Jack can sell Jack's vehicle? -> #{DeclarativePolicy.policy_for(jack, jacks_vehicle).can?(:sell_vehicle)}"
puts "Jack can sell Jill's vehicle? -> #{DeclarativePolicy.policy_for(jack, jills_vehicle).can?(:sell_vehicle)}"
$ ruby example.rb
Jack can drive Jack's vehicle? -> true
Jack can drive Jill's vehicle? -> true
Jack can sell Jack's vehicle? -> true
Jack can sell Jill's vehicle? -> false
Die Kernabstraktion dieser Bibliothek ist eine Policy. Richtlinien kombinieren:
conditions) über den Zustand der Weltrules)Diese Bibliothek dient dazu, den Wahrheitswert von Aussagen der folgenden Form zu bestimmen:
Benutzer Prädikat [Subjekt]
Die Umbenennung von Benutzer in Akteur und Subjekt in Ressource wird in
diesem Issue diskutiert.
Zum Beispiel:
user :is_aliveuser :can_drive caruser :can_sell carDies geschieht, indem wir einer Policy (einer Sammlung von Regeln darüber, welche
Aussagen wahr sind) erlauben, den Objekten der Sätze zugeordnet zu werden. Eine Aussage gilt
als zutreffend, wenn keine Regel sie prevent und mindestens eine Regel sie enable.
Angenommen, wir haben ein Datenmodell mit Fahrzeugen und Benutzern und möchten
wissen, ob ein Benutzer ein Fahrzeug fahren darf. Wir benötigen eine VehiclePolicy:
class VehiclePolicy < DeclarativePolicy::Base
# relevante Fakten
condition(:owns) { @subject.owner == @user }
condition(:has_access_to) { @subject.owner.trusts?(@user) }
condition(:old_enough_to_drive) { @user.age >= laws.minimum_age }
condition(:has_driving_license) { @user.driving_license&.valid? }
# aufwändige Regeln können einen 'score' haben. Höhere Scores sind 'teurer' zu berechnen
condition(:owns, score: 0) { @subject.owner == @user }
condition(:has_access_to, score: 3) { @subject.owner.trusts?(@user) }
condition(:intoxicated, score: 5) { @user.blood_alcohol > laws.max_blood_alcohol }
# Schlussfolgerungen, die wir ziehen können:
rule { owns }.enable :drive_vehicle
rule { has_access_to }.enable :drive_vehicle
rule { ~old_enough_to_drive }.prevent :drive_vehicle
rule { intoxicated }.prevent :drive_vehicle
rule { ~has_driving_license }.prevent :drive_vehicle
# Wir können Methoden verwenden, um gemeinsame Logik zu abstrahieren
def laws
@subject.registration.country.driving_laws
end
end
Einige Punkte sind zu beachten: Wir hätten dies auch als eine große Regel schreiben können
((owns | has_access_to) & old_enough_to_drive & ~intoxicated & has_driving_license),
aber wir sehen einige der Funktionen, die deklarative Richtlinien für große
Systeme skalierbar machen: Regeln können in kleine Elemente aufgeteilt und zu
größeren Regeln zusammengesetzt werden. Neue Bedingungen und Regeln können jederzeit hinzugefügt werden.
Was schwieriger zu sehen ist, ist, dass viele Leistungsoptimierungen für uns transparent behandelt werden:
Kurz gesagt zielt diese Bibliothek darauf ab, deklarativ zu sein: Wir deklarieren die Regeln, die wichtig sind, und die Bibliothek arrangiert, wie sie ausgewertet werden.
Caching ist eine besonders wertvolle Eigenschaft von Richtlinien. Wenn wir neue Regeln zum Verkauf eines Fahrzeugs hinzufügen, zum Beispiel:
rule { owns }.enable :sell_vehicle
Dann kann die Tatsache des Besitzes zwischen verschiedenen Aufrufen der Richtlinie geteilt werden, was Datenbankaufrufe und andere teure E/A-Operationen spart.
Wir können die Entscheidung einer Richtlinie wie folgt überprüfen:
cache = Session.current_session
policy = DeclarativePolicy.policy_for(user, car, cache: cache)
policy.can?(:drive_vehicle)
Weitere Nutzungsdetails finden Sie in der Dokumentation.
Nachdem Sie das Repository ausgecheckt haben, führen Sie bundle install aus, um die Abhängigkeiten zu installieren.
Führen Sie dann rake spec aus, um die Tests auszuführen. Sie können auch bin/console für eine
interaktive Eingabeaufforderung verwenden, mit der Sie experimentieren können.
Um dieses Gem auf Ihrem lokalen Rechner zu installieren, führen Sie bundle exec rake install aus. Um eine neue Version zu veröffentlichen, aktualisieren Sie die Versionsnummer in version.rb und führen Sie dann bundle exec rake release aus. Dadurch wird ein Git-Tag für die Version erstellt, Git-Commits und Tags gepusht und die .gem-Datei an rubygems.org gepusht.
Weitere Details zu Richtlinien und benutzerdefinierten Rollen finden Sie auf den folgenden Seiten:
Fehlerberichte und Merge Requests sind auf GitLab willkommen unter https://gitlab.com/gitlab-org/ruby/gems/declarative-policy. Dieses Projekt soll ein sicherer, einladender Raum für Zusammenarbeit sein, und Mitwirkende werden gebeten, den GitLab-Verhaltenskodex einzuhalten.
Wir veröffentlichen declarative_policy nach Bedarf. Es gibt keine Regelmäßigkeit, wann
wir veröffentlichen, wir veröffentlichen einfach, wenn wir eine Änderung vornehmen – unabhängig von der Größe der
Änderung.
So veröffentlichen Sie eine neue Version:
declarative_policy Ruby-Gem auf die neue Version zu aktualisieren.Das Gem ist als Open Source unter den Bedingungen der MIT-Lizenz verfügbar.
Von jedem, der an der Codebasis des DeclarativePolicy-Projekts, den Issue-Trackern,
Chat-Räumen und Mailinglisten mitwirkt, wird erwartet, dass er den
Verhaltenskodex einhält.