Attributbasierte Filter
Kurzantwort: Ein Attributfilter verknüpft ein Attribut des
Benutzerprofils (z. B. projects) mit einem Datenfeld des Modells (z. B.
projectId). Der Benutzer sieht nur Zeilen, deren Feldwert in seinen
Attributwerten vorkommt. Ein * im Attribut hebt die Einschränkung auf; ein
fehlendes oder leeres Attribut führt zum Fehler – niemals zu vollem Zugriff.
Rollen sagen „darf Kunden lesen”. Attributfilter sagen „darf diese Kunden lesen” – ohne für jedes Projekt, jede Filiale oder jeden Bereich eine eigene Rolle anzulegen.
Deklaration
Abschnitt betitelt „Deklaration“Am Modell:
@AccessByAttribute(attribute = "projects", field = "projectId")attribute ist der Name des Profilattributs, field der Feldpfad im Modell
(auch company.id ist möglich).
Der Generator erzeugt daraus einen {Model}AttributeFilter, der von
AbstractAttributeFilter<T> erbt und als Spring-Bean vorliegt. Der System-Layer
sammelt alle CdmsFilterInterface-Beans des Modells ein und hängt ihre Filter
an jede Abfrage.
Auflösungsregeln
Abschnitt betitelt „Auflösungsregeln“flowchart TB
A["Profilattribut lesen"] --> B{"vorhanden?"}
B -->|nein| E1["422 missing-attribute-on-profile"]
B -->|ja| C["Werte zerlegen:<br/>mehrere Einträge und/oder<br/>kommaseparierte Werte"]
C --> D{"enthält '*'?"}
D -->|ja| N["kein Filter – alle Zeilen sichtbar"]
D -->|nein| F{"Anzahl Werte"}
F -->|0| E2["422 empty-attribute-on-profile"]
F -->|1| EQ["Filter: feld EQ wert"]
F -->|">1"| IN["Filter: feld IN wert1,wert2,…"]
| Fall | Ergebnis |
|---|---|
| Attribut fehlt im Profil | AttributeValidationException (422) – kein Zugriffsrecht, also keine Daten |
| Attribut vorhanden, aber ohne brauchbaren Wert | AttributeValidationException (422) – ein leeres Recht ist ein kaputtes Profil, kein Vollzugriff |
mindestens ein Wert ist * | kein Filter – der Aufrufer sieht alles |
| genau ein Wert | EQ auf dem Datenfeld |
| mehrere Werte | IN auf dem Datenfeld |
Die Werte dürfen als mehrere Array-Einträge, als ein kommaseparierter Eintrag oder gemischt kommen; Leerzeichen werden getrimmt, Duplikate entfernt.
Woher die Attribute kommen
Abschnitt betitelt „Woher die Attribute kommen“Aus dem Token: Keycloak bildet Benutzerattribute auf Claims ab. Der
TokenParser übernimmt jeden Claim, der kein Protokoll-Claim ist, als
Benutzerattribut nach RequestContext.effectiveUserAttributes – immer als
String[].
// Ausschnitt aus dem Token{ "projects": ["a1b2", "c3d4"], "region": "nord" }Was der Server tatsächlich sieht, zeigt GET /cias/fetch.
Zusammenspiel mit anderen Filtern
Abschnitt betitelt „Zusammenspiel mit anderen Filtern“Alle Filter werden mit AND an die Wurzel der Abfrage gehängt:
(Client-Query) AND _userId = <benutzer> AND projectId IN (a1b2, c3d4)Sie sind als mandatory markiert – ein Filter, der sich nicht in ein Prädikat übersetzen lässt, bringt die Anfrage zum Scheitern statt weggelassen zu werden. Ein weggelassener Sicherheitsfilter würde alle Zeilen liefern.
Der Filter wirkt außerdem beim Schreiben: assertVisibleForWrite(id) prüft mit
demselben Filtersatz, ob die Zeile überhaupt sichtbar ist – sonst 404.
Eigene Filter
Abschnitt betitelt „Eigene Filter“Für Logik jenseits eines einfachen Attributvergleichs lässt sich
CdmsFilterInterface<T> direkt implementieren; siehe
Eigene Filter.