Zugriffsfilter (Permission Filter)¶
Ein Zugriffsfilter legt fest, welche Inhalte und Zeilen eine Person oder Gruppe innerhalb eines Spaces sehen darf. Er ergänzt die normale Mitgliedschaft und Rolle um eine fachliche Einschränkung – und dient gleichzeitig als harte Sicherheitsgrenze.
Technisch ist er ein JSON-Objekt, das als Allowlist funktioniert:
- Du gibst Tabellen explizit frei – oder implizit über einen Spaltenfilter.
- Du schränkst freigegebene Tabellen bei Bedarf weiter ein.
- Alles, was nicht freigegeben ist, bleibt unsichtbar.
Wann brauchst du einen Zugriffsfilter?¶
Typische Fälle:
- jemand soll nur Inhalte für einen bestimmten Kunden, ein Projekt oder einen Standort sehen
- ein Nutzer darf nur bestimmte Tabellen sehen
- ein Team darf nur Datensätze eines Mandanten sehen
- öffentliche Tabellen sollen für viele Rollen sichtbar sein
- ein eingebetteter Assistent soll nur den fachlich passenden Kontext nutzen dürfen
- ein Space darf zwar auf eine Datenquelle zugreifen, aber nur auf einen Teil der Zeilen
Wie funktioniert das Prinzip?¶
Ein Zugriffsfilter folgt einer einfachen Denkweise:
- Lege fest, welche Merkmale Inhalte haben müssen, damit sie sichtbar sein dürfen.
- Halte die Regeln so einfach und nachvollziehbar wie möglich.
- Prüfe die Regeln aus Sicht der Zielgruppe und nicht nur aus Sicht der Ersteller.
Der Filter wird als Allowlist ausgewertet: Sobald ein Permission Filter nicht leer ist, werden Tabellen ohne passende Freigabe blockiert. Ein leerer Filter bedeutet keine zusätzliche Einschränkung – dann greift nur die normale Mitgliedschaft.
Gute fachliche Fragen vor dem Einrichten¶
Bevor du einen Zugriffsfilter anlegst, kläre diese Punkte:
- Welche Personengruppe soll welche Inhalte sehen?
- Nach welchen fachlichen Merkmalen lassen sich Inhalte sauber unterscheiden?
- Sind diese Merkmale in euren Inhalten zuverlässig gepflegt?
- Ist ein eigener Space vielleicht einfacher als ein komplexer Filter?
Wenn diese Fragen nicht klar beantwortet sind, wird ein Zugriffsfilter schnell unübersichtlich oder fehleranfällig.
Technischer Aufbau¶
Grundaufbau¶
Ein Permission Filter ist normales JSON. Es gibt zwei Wege, einer Tabelle Zugriff zu gewähren:
Explizit – wenn eine Tabelle vollständig ohne Zeileneinschränkung freigegeben werden soll:
Implizit über einen Spaltenfilter – ein Eintrag der Form tabelle.spalte gewährt automatisch Zugriff auf die Tabelle und schränkt gleichzeitig die sichtbaren Zeilen ein. Ein zusätzlicher table-Eintrag ist dabei nicht nötig:
Dieses Beispiel bedeutet: die Tabelle orders ist erlaubt, aber nur Zeilen mit customer_id 1001 oder 1002.
Wichtig: Sobald mehrere Tabellen zusammen freigegeben werden sollen, müssen alle Einträge in einem or stehen:
Die drei wichtigsten Bausteine¶
1. Tabellen direkt freigeben¶
Ein expliziter table-Eintrag ist sinnvoll, wenn eine Tabelle vollständig (ohne Zeileneinschränkung) freigegeben werden soll.
Eine einzelne Tabelle:
Mehrere Tabellen:
{
"or": [
{ "table": { "eq": "orders" } },
{ "table": { "eq": "customers" } },
{ "table": { "eq": "invoices" } }
]
}
2. Tabellen über Facets oder Tags freigeben¶
Wenn dein Datenbankschema Tabellen mit Tags oder Facets beschreibt, kannst du ganze Gruppen von Tabellen freigeben.
Das erlaubt alle Tabellen, die im Schema das Facet public: true haben oder das Tag public tragen.
{ "eq": false } wird als gültige Form erkannt, gibt aber absichtlich keine Tabelle frei. Facet- und Tag-Einträge erzeugen selbst keine zusätzliche WHERE-Bedingung, sondern erweitern nur die Menge erlaubter Tabellen.
3. Zeilen innerhalb einer Tabelle einschränken¶
Ein Spaltenfilter der Form tabelle.spalte gewährt implizit Zugriff auf die Tabelle und schränkt gleichzeitig die sichtbaren Zeilen ein:
Mehrere Spaltenfilter für dieselbe Tabelle können direkt nebeneinander stehen – sie werden per AND verknüpft:
Sobald verschiedene Tabellen betroffen sind, müssen die Einträge in ein or:
Unterstützte Operatoren¶
| Operator | Bedeutung | Beispiel |
|---|---|---|
eq |
gleich | { "orders.status": { "eq": "open" } } |
ne |
ungleich | { "orders.status": { "ne": "cancelled" } } |
gt |
größer als | { "orders.amount": { "gt": 0 } } |
lt |
kleiner als | { "orders.amount": { "lt": 1000 } } |
gte |
größer oder gleich | { "orders.amount": { "gte": 100 } } |
lte |
kleiner oder gleich | { "orders.amount": { "lte": 500 } } |
in |
Wert ist in einer Liste | { "orders.customer_id": { "in": [1, 2, 3] } } |
like |
Textmuster | { "files.path": { "like": "%/angebote/%" } } |
Zusätzlich gilt:
{ "eq": null }entsprichtIS NULL{ "ne": null }entsprichtIS NOT NULL
Logische Verknüpfungen¶
Filter können mit and, or und not verschachtelt werden. Mehrere Tabellen müssen immer über or zusammengeführt werden:
Das ist nützlich, wenn ein Space sowohl eine konkrete Tabelle als auch alle Tabellen mit dem Tag oder Facet public sehen darf.
Mehrere Zugriffsquellen werden vereinigt¶
Wenn ein Nutzer über direkte Mitgliedschaft und über Gruppenmitgliedschaften Zugriff erhält, werden die jeweiligen Filter per OR zusammengeführt. So sieht ein Nutzer die Vereinigung aller Quellen, über die er Zugriff erhält.
Schemaqualifizierte Tabellennamen¶
Wenn deine SQL-Abfragen Namen wie public.orders oder analytics.sales verwenden, kannst du beide Schreibweisen nutzen:
Beides ist für solche Tabellen geeignet.
Beispiele¶
Beispiel 1: Nur Bestellungen eines Mandanten¶
Beispiel 2: Kunden und Rechnungen für bestimmte Organisationen¶
{
"or": [
{ "customers.organization_id": { "in": [7, 8] } },
{ "invoices.organization_id": { "in": [7, 8] } }
]
}
Beispiel 3: Öffentliche Tabellen über Tag oder Facet freigeben¶
Praktisch für Stammdaten, Referenztabellen oder kontrolliert freigegebene Reporting-Tabellen, die viele Rollen lesen dürfen.
Beispiel 4: Öffentliche Tabellen freigeben und zusätzlich eine nicht-öffentliche Tabelle eingeschränkt zugänglich machen¶
Bedeutung: alle als public markierten Tabellen sind frei zugänglich, zusätzlich ist die Tabelle customers erlaubt – aber nur Zeilen mit status = active.
Beispiel 5: Dateien nur aus einem bestimmten Pfad¶
Beispiel 6: Nur nicht gelöschte Datensätze¶
Beispiel 7: Alles aus einer Kategorie außer archivierte Einträge¶
Beide Bedingungen betreffen dieselbe Tabelle und werden per AND verknüpft.
Beispiel 8: Wertebereich für Reporting¶
Mehrere Operatoren in einem Feld werden gemeinsam angewendet.
Beispiel 9: Liste erlaubter IDs¶
Beispiel 10: Konkrete Tabelle und öffentliche Tabellen gleichzeitig¶
Beispiel 11: Zwei Tabellen im Join, jede mit Zeileneinschränkung¶
{
"or": [
{ "orders.customer_id": { "in": [1001, 1002] } },
{ "customers.country": { "eq": "DE" } }
]
}
Beispiel 12: Nur offene Aufgaben (kein Abschlussdatum)¶
Beispiel 13: Nur abgeschlossene Aufgaben¶
Beispiel 14: Tabellen über einen internen Tag freigeben¶
Damit werden alle Tabellen freigegeben, die das Tag internal tragen oder im Schema das Facet internal: true haben.
Beispiel 15: Öffentliche Tabellen plus eine Spezialtabelle¶
Was bei Joins wichtig ist¶
Bei einer Abfrage mit mehreren Tabellen muss jede verwendete Tabelle freigegeben sein.
Das reicht für:
Das reicht nicht für:
Denn customers ist hier nicht freigegeben. Wenn du Joins erlauben willst, müssen alle beteiligten Tabellen im Filter stehen:
Einfache Pflege in der UI¶
Die einfache UI arbeitet typischerweise mit einer Liste von Tabellen und einer Liste von Facets oder Tags. Sie erzeugt daraus intern JSON wie dieses:
{
"or": [
{ "table": { "eq": "orders" } },
{ "table": { "eq": "customers" } },
{ "public": { "eq": true } },
{ "internal": { "eq": true } }
]
}
Nicht jede beliebige JSON-Form ist in diese einfache UI zurückführbar. Wenn dein Fall komplexer ist, kannst du den Filter direkt als JSON pflegen.
Häufige Stolperfallen¶
1. Nicht-leerer Filter blockiert alles, was nicht freigegeben ist¶
Das ist Absicht. Permission Filter sind keine lose Empfehlung, sondern eine harte Sicherheitsgrenze.
2. Regeln sind fachlich nicht sauber abgestimmt¶
Wenn Inhalte die nötigen Merkmale nicht konsistent tragen, greift der Filter unerwartet oder gar nicht.
3. Mehrere Tabellen ohne or auf oberster Ebene¶
Das ist nicht korrekt für zwei verschiedene Tabellen. Die Einträge müssen in einem or stehen:
4. Ein leeres in blockiert immer¶
So ein Filter lässt für diese Bedingung keine Zeile übrig.
5. { "eq": false } bei Facets oder Tags gibt nichts frei¶
Das ist keine Negation, sondern praktisch eine leere Freigabe.
6. search ist kein Permission-Mechanismus¶
Der Schlüssel search ist für andere Filterzwecke gedacht und sollte nicht als Sicherheitsregel verwendet werden.
7. Ein leerer Filter bedeutet keine zusätzliche Einschränkung¶
Dann greift nur die normale Mitgliedschaft, aber kein zusätzlicher Permission-Filter.
8. Zu viele Sonderfälle in einem einzelnen Filter¶
Wenn ein Filter sehr viele Ausnahmen enthält, ist oft ein eigener Space die bessere Lösung.
Empfehlungen¶
Für neue Filter¶
Bewährte Reihenfolge:
- Überlege, ob Tabellen vollständig oder nur eingeschränkt zugänglich sein sollen.
- Nutze Spaltenfilter (
tabelle.spalte) dort, wo Zeilen eingeschränkt werden sollen – sie gewähren die Tabelle implizit mit. - Nutze explizite
table.eq-Einträge nur für Tabellen ohne Zeileneinschränkung. - Fasse mehrere Tabellen immer in einem
orzusammen. - Verwende Facets oder Tags für stabile, gleichartige Tabellengruppen.
- Komplexe
and-/or-/not-Bäume nur einsetzen, wenn die technische Semantik bekannt ist.
Für Teams¶
- Einigt euch auf wenige, klare Merkmale für Sichtbarkeit.
- Verwendet überall dieselben Begriffe für Kunde, Projekt, Bereich oder Freigabestatus.
- Testet die Sichtbarkeit immer mit realen Beispielnutzern.
- Dokumentiert kurz, warum ein bestimmter Filter existiert.
- Überprüft nach Änderungen an Rollen, Zielgruppen oder Datenquellen, ob der Filter noch passt.
Wann du lieber einfacher startest¶
Ein Zugriffsfilter ist nicht immer die beste erste Lösung. Häufig ist etwas anderes einfacher:
- eigener Space statt vieler Ausnahmen in einem gemeinsamen Space
- klar getrennte Assistenten statt ein Assistent mit zu vielen Sonderfällen
- saubere Ablagestruktur statt komplizierter Nachfilterung
Kurzcheck vor dem Speichern¶
Prüfe bei jedem neuen Filter:
- Sind alle benötigten Tabellen freigegeben – entweder per
table.eq, Facet/Tag oder Spaltenfilter? - Stehen alle Einträge für verschiedene Tabellen in einem
or? - Sind Joins mit allen beteiligten Tabellen abgedeckt?
- Sind Mandanten-, Kunden- oder Organisationsgrenzen sauber als Spaltenfilter gesetzt?
- Verwende ich Tags oder Facets dort, wo viele Tabellen dieselbe Regel teilen?
- Ist der Filter so einfach, dass andere ihn später noch sicher lesen können?