Feingranulare Autorisierungs-API (FGA)
Die Feingranulare-Autorisierungs-Engine bietet Zanzibar-style beziehungsbasierte Zugriffssteuerung (ReBAC). Sie erweitert die RBAC-Schicht um objektbasierte Autorisierung: Anstatt “Benutzer hat Berechtigung X global” beantwortet FGA: “Hat Benutzer Alice die Relation viewer auf Dokument readme?”
Das System basiert auf drei Konzepten:
- Autorisierungsmodelle definieren Objekttypen, ihre Relationen und Umschreibungsregeln mithilfe eines OpenFGA-kompatiblen DSL.
- Beziehungs-Tupel sind die Fakten des Systems. Jedes Tupel stellt fest, dass ein Subjekt eine Beziehung zu einem Objekt hat.
- Autorisierungsabfragen (
check,expand,list-objects) werten Tupel anhand der Umschreibungsregeln des Modells aus.
Alle FGA-Endpunkte erfordern den x-tenant-Header und ein gültiges Zugriffs-Token.
Autorisierungsmodell-DSL
Das DSL definiert Typen und ihre Relationen. Jede Relation kann Umschreibungsregeln haben, die den Zugang aus anderen Relationen oder indirekten Beziehungen zusammensetzen.
type user
type group
relations
define member: [user]
type document
relations
define owner: [user]
define editor: [user, group#member]
define viewer: [user, group#member] or editor or ownerUmschreibungsregel-Typen:
| Regel | Syntax | Beschreibung |
|---|---|---|
Direkt (this) | [user] | Subjekt muss direkt über ein Tupel zugewiesen sein |
| Union | A or B | Subjekt muss mindestens eine der Relationen erfüllen |
| Intersection | A and B | Subjekt muss alle Relationen erfüllen |
| Exclusion | A but not B | Subjekt muss A erfüllen und darf B nicht erfüllen |
| Computed Userset | owner | Erbt von einer anderen Relation auf demselben Objekt |
| Tuple-to-Userset | group#member | Folgt einer Relation auf einem verwandten Objekt (indirekt) |
Die FGA-Engine verwendet rekursive Auswertung mit einer maximalen Tiefe von 25 und Zykluserkennung über ein besuchtes Set. Dies verhindert Endlosschleifen in zirkulären Relationsdefinitionen.
Autorisierungsmodelle
Modelle auflisten
/api/fga/modelsRequires: view:fga_modelsAlle Autorisierungsmodelle für den Tenant auflisten, nach Version absteigend geordnet. Es kann nur ein Modell gleichzeitig aktiv sein. Das aktive Modell wird für alle Tupelvalidierungen und Autorisierungsabfragen verwendet.
Abfrageparameter
| Parameter | Typ | Beschreibung |
|---|---|---|
page | integer | Seitennummer (Standard: 1) |
limit | integer | Elemente pro Seite (Standard: 20) |
Erfolgsantwort
{
"ok": true,
"data": [
{
"id": "model_abc123",
"name": "SaaS-Autorisierungsmodell",
"version": 3,
"isActive": true,
"createdAt": "2025-02-10T00:00:00Z",
"updatedAt": "2025-02-12T08:30:00Z"
},
{
"id": "model_def456",
"name": "SaaS-Autorisierungsmodell",
"version": 2,
"isActive": false,
"createdAt": "2025-02-05T00:00:00Z",
"updatedAt": "2025-02-05T00:00:00Z"
}
]
}Modell erstellen
/api/fga/modelsRequires: manage:fga_modelsEin neues Autorisierungsmodell erstellen, indem ein Name und eine DSL-Definition bereitgestellt werden. Das DSL wird zeilenweise geparst und vor der Speicherung validiert. Wenn das DSL Syntaxfehler enthält oder undefinierte Typen oder Relationen referenziert, wird die Anforderung mit einer detaillierten Fehlermeldung einschließlich der Zeilennummer abgelehnt.
Anforderungs-Body
{
"name": "Dokumentzugriffsmodell",
"dsl": "type user\n\ntype group\n relations\n define member: [user]\n\ntype document\n relations\n define owner: [user]\n define editor: [user, group#member]\n define viewer: [user, group#member] or editor or owner\n"
}Erfolgsantwort
{
"ok": true,
"data": {
"id": "model_ghi789",
"name": "Dokumentzugriffsmodell",
"version": 1,
"isActive": false,
"dsl": "type user\n\ntype group\n relations\n define member: [user]\n\ntype document\n relations\n define owner: [user]\n define editor: [user, group#member]\n define viewer: [user, group#member] or editor or owner\n",
"schema": {
"typeDefinitions": [
{
"type": "user",
"relations": {}
},
{
"type": "group",
"relations": {
"member": { "this": {} }
}
},
{
"type": "document",
"relations": {
"owner": { "this": {} },
"editor": { "this": {} },
"viewer": {
"union": {
"children": [
{ "this": {} },
{ "computedUserset": { "relation": "editor" } },
{ "computedUserset": { "relation": "owner" } }
]
}
}
}
}
]
},
"createdAt": "2025-02-18T10:00:00Z"
}
}Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
DSL_PARSE_ERROR | 400 | DSL-Syntax ist ungültig. Das message-Feld enthält die Zeilennummer und Beschreibung des Fehlers |
DSL_VALIDATION_ERROR | 400 | DSL ist syntaktisch korrekt, referenziert aber undefinierte Typen, Relationen oder enthält Zyklen |
VALIDATION_ERROR | 400 | Fehlende Pflichtfelder (name oder dsl) |
DSL-Parse-Fehler-Beispiel
{
"ok": false,
"error": {
"code": "DSL_PARSE_ERROR",
"message": "Zeile 7: Unbekanntes Schlüsselwort 'defines'. Meintest du 'define'?"
}
}Modell abrufen
/api/fga/models/[id]Requires: view:fga_modelsEin bestimmtes Autorisierungsmodell anhand seiner ID abrufen. Gibt das vollständige Modell zurück, einschließlich des rohen DSL-Texts und des geparsten Schema-Objekts.
Erfolgsantwort
{
"ok": true,
"data": {
"id": "model_ghi789",
"name": "Dokumentzugriffsmodell",
"version": 1,
"isActive": false,
"dsl": "type user\n\ntype group\n relations\n define member: [user]\n...",
"schema": {
"typeDefinitions": [
{ "type": "user", "relations": {} },
{ "type": "group", "relations": { "member": { "this": {} } } },
{ "type": "document", "relations": { "owner": { "this": {} }, "editor": { "this": {} }, "viewer": { "union": {} } } }
]
},
"createdAt": "2025-02-18T10:00:00Z",
"updatedAt": "2025-02-18T10:00:00Z"
}
}Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NOT_FOUND | 404 | Modell existiert nicht oder gehört einem anderen Tenant |
Modell aktualisieren
/api/fga/models/[id]Requires: manage:fga_modelsDen Namen oder die DSL-Definition eines Modells aktualisieren. Wenn das DSL aktualisiert wird, wird es erneut geparst und validiert. Die Version des Modells wird bei einer Aktualisierung nicht automatisch erhöht — erstelle ein neues Modell für versionierte Änderungen.
Anforderungs-Body
{
"name": "Dokumentzugriffsmodell v2",
"dsl": "type user\n\ntype document\n relations\n define owner: [user]\n define viewer: [user] or owner\n"
}name und dsl sind optional. Nur bereitgestellte Felder werden aktualisiert.
Erfolgsantwort
{
"ok": true,
"data": {
"id": "model_ghi789",
"name": "Dokumentzugriffsmodell v2",
"version": 1,
"isActive": false,
"schema": { "typeDefinitions": [] },
"updatedAt": "2025-02-18T11:00:00Z"
}
}Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NOT_FOUND | 404 | Modell existiert nicht |
DSL_PARSE_ERROR | 400 | Aktualisiertes DSL hat Syntaxfehler |
DSL_VALIDATION_ERROR | 400 | Aktualisiertes DSL referenziert undefinierte Typen oder Relationen |
Modell löschen
/api/fga/models/[id]Requires: manage:fga_modelsEin Autorisierungsmodell löschen. Aktive Modelle können nicht gelöscht werden — du musst zunächst ein anderes Modell aktivieren.
Das Löschen eines Modells löscht nicht automatisch Tupel, die dagegen geschrieben wurden. Verwaiste Tupel werden von Autorisierungsabfragen ignoriert, verbleiben aber in der Datenbank, bis sie manuell bereinigt werden.
Erfolgsantwort
{
"ok": true,
"data": { "deleted": true }
}Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NOT_FOUND | 404 | Modell existiert nicht |
MODEL_IS_ACTIVE | 400 | Das aktuell aktive Modell kann nicht gelöscht werden |
Modell aktivieren
/api/fga/models/[id]/activateRequires: manage:fga_modelsEin Modell als das aktive Autorisierungsmodell für den Tenant setzen. Jedes zuvor aktive Modell
wird automatisch deaktiviert. Alle nachfolgenden check-, expand- und list-objects-Abfragen
verwenden die Umschreibungsregeln des neu aktivierten Modells. Der Modell-Cache wird sofort
invalidiert.
Anforderung: Kein Body erforderlich.
Erfolgsantwort
{
"ok": true,
"data": {
"activated": true,
"modelId": "model_ghi789"
}
}Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NOT_FOUND | 404 | Modell existiert nicht |
ALREADY_ACTIVE | 400 | Dieses Modell ist bereits das aktive Modell |
Die FGA-Engine cached das aktive Modell im Speicher mit einer TTL von 5 Minuten. Nach der Aktivierung eines neuen Modells können Abfragen auf anderen Server-Instanzen bis zu 5 Minuten lang das alte Modell verwenden. Force-Refresh erfolgt sofort auf der Instanz, die die Aktivierungsanforderung verarbeitet hat.
Beziehungs-Tupel
Tupel sind die Autorisierungsfakten. Jedes Tupel gibt an, dass ein Subjekt eine Beziehung zu einem Objekt hat.
Tupel-Format: objektTyp:objektId#relation@subjektTyp:subjektId
Beispiele:
document:readme#viewer@user:alice— Alice ist ein Viewer des Dokuments “readme”document:readme#editor@group:engineering#member— Mitglieder der Gruppe “engineering” sind Editoren des Dokuments “readme”folder:projects#owner@user:bob— Bob besitzt den Ordner “projects”
Tupel auflisten
/api/fga/tuplesRequires: view:fga_tuplesBeziehungs-Tupel mit optionaler Filterung auflisten. Mindestens ein Filterparameter wird empfohlen, um zu vermeiden, den gesamten Tupel-Speicher zurückzugeben. Unterstützt Paginierung.
Abfrageparameter
| Parameter | Typ | Beschreibung |
|---|---|---|
objectType | string | Nach Objekttyp filtern (z.B. document) |
objectId | string | Nach Objekt-ID filtern |
relation | string | Nach Relationsname filtern |
subjectType | string | Nach Subjekttyp filtern |
subjectId | string | Nach Subjekt-ID filtern |
page | integer | Seitennummer (Standard: 1) |
limit | integer | Elemente pro Seite (Standard: 20, max: 100) |
Erfolgsantwort
{
"ok": true,
"data": {
"data": [
{
"id": "tuple_abc123",
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice",
"subjectRelation": null,
"createdAt": "2025-02-15T10:00:00Z"
},
{
"id": "tuple_def456",
"objectType": "document",
"objectId": "readme",
"relation": "editor",
"subjectType": "group",
"subjectId": "engineering",
"subjectRelation": "member",
"createdAt": "2025-02-15T10:05:00Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 2,
"totalPages": 1
}
}
}Tupel schreiben
/api/fga/tuplesRequires: manage:fga_tuplesEin einzelnes Beziehungs-Tupel schreiben. Das Tupel wird vor der Speicherung gegen das aktive Autorisierungsmodell validiert. Der Objekttyp, die Relation und der Subjekttyp müssen im aktiven Modell existieren, und die Relation muss den Subjekttyp als gültiges Zuweisungsziel akzeptieren.
Anforderungs-Body — direkte Benutzerzuweisung
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice"
}Anforderungs-Body — Subjektmenge (indirekt/Gruppenmitgliedschaft)
Wenn das Subjekt kein einzelner Benutzer ist, sondern eine Menge von Benutzern, die durch eine Relation auf einem anderen Objekt definiert ist, schließe subjectRelation ein:
{
"objectType": "document",
"objectId": "readme",
"relation": "editor",
"subjectType": "group",
"subjectId": "engineering",
"subjectRelation": "member"
}Das bedeutet: “Alle Entitäten, die die member-Relation auf group:engineering haben, sind auch editor auf document:readme.”
Erfolgsantwort
{
"ok": true,
"data": {
"id": "tuple_ghi789",
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice",
"subjectRelation": null,
"createdAt": "2025-02-18T10:00:00Z"
}
}Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NO_ACTIVE_MODEL | 400 | Kein aktives Autorisierungsmodell für diesen Tenant |
INVALID_TYPE | 400 | Objekttyp existiert nicht im aktiven Modell |
INVALID_RELATION | 400 | Relation existiert nicht auf diesem Objekttyp im aktiven Modell |
INVALID_SUBJECT_TYPE | 400 | Die Relation akzeptiert diesen Subjekttyp nicht als gültiges Ziel |
TUPLE_EXISTS | 409 | Ein identisches Tupel existiert bereits |
VALIDATION_ERROR | 400 | Fehlende Pflichtfelder |
Tupel löschen
/api/fga/tuplesRequires: manage:fga_tuplesEin bestimmtes Beziehungs-Tupel löschen, indem die Tupeldaten im Anforderungs-Body angegeben werden. Alle Tupelfelder müssen exakt übereinstimmen. Gibt Erfolg zurück, auch wenn das Tupel nicht existiert (idempotentes Löschen).
Anforderungs-Body
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice"
}Erfolgsantwort
{
"ok": true,
"data": { "deleted": true }
}Tupel massenweise schreiben/löschen
/api/fga/tuples/bulkRequires: manage:fga_tuplesMehrere Tupel in einer einzigen atomaren Anforderung schreiben und/oder löschen. Alle Operationen im Batch werden gegen das aktive Modell validiert, bevor Schreibvorgänge erfolgen. Wenn ein einzelnes Tupel die Validierung nicht besteht, wird der gesamte Batch abgelehnt und keine Änderungen vorgenommen.
Anforderungs-Body
{
"writes": [
{
"objectType": "document",
"objectId": "api-spec",
"relation": "owner",
"subjectType": "user",
"subjectId": "bob"
},
{
"objectType": "document",
"objectId": "api-spec",
"relation": "viewer",
"subjectType": "group",
"subjectId": "engineering",
"subjectRelation": "member"
}
],
"deletes": [
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice"
}
]
}writes und deletes sind optional, aber mindestens eines muss vorhanden sein. Jedes Array kann bis zu 100 Tupel enthalten.
Erfolgsantwort
{
"ok": true,
"data": {
"written": 2,
"deleted": 1
}
}Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NO_ACTIVE_MODEL | 400 | Kein aktives Autorisierungsmodell |
INVALID_RELATION | 400 | Ein Tupel referenziert eine Relation, die nicht im aktiven Modell existiert |
INVALID_TYPE | 400 | Ein Tupel referenziert einen Objekttyp, der nicht im aktiven Modell ist |
BATCH_TOO_LARGE | 400 | Gesamt-Writes + Deletes überschreitet die maximale Batch-Größe |
VALIDATION_ERROR | 400 | Ein oder mehrere Tupel haben fehlende Pflichtfelder |
Bulk-Operationen sind atomar. Wenn Tupel #47 von 100 die Validierung nicht besteht, wird keines der 100 Tupel geschrieben oder gelöscht. Prüfe die Fehlerantwort für das spezifisch fehlgeschlagene Tupel.
Autorisierungsabfragen
Check
/api/fga/checkRequires: debug:fgaPrüfen, ob ein Subjekt eine bestimmte Relation zu einem Objekt hat. Die Engine wertet die vollständigen Umschreibungsregeln des aktiven Modells rekursiv aus und folgt dabei Computed Usersets, Tuple-to-Userset-Indirektionen, Unions, Intersections und Exclusions. Gibt optional einen Auflösungsbaum zurück, der zeigt, wie die Entscheidung getroffen wurde.
Anforderungs-Body
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice",
"explain": false
}| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
objectType | string | Ja | Der Typ des Zielobjekts |
objectId | string | Ja | Die ID des Zielobjekts |
relation | string | Ja | Die zu prüfende Relation |
subjectType | string | Ja | Der Typ des Subjekts (typischerweise user) |
subjectId | string | Ja | Die ID des Subjekts |
explain | boolean | Nein | Wenn true, wird der Auflösungsbaum eingeschlossen (Standard: false) |
Erfolgsantwort (ohne Erklärung)
{
"ok": true,
"data": {
"allowed": true
}
}Erfolgsantwort (mit Erklärung)
{
"ok": true,
"data": {
"allowed": true,
"resolution": {
"type": "union",
"relation": "viewer",
"result": true,
"children": [
{
"type": "this",
"relation": "viewer",
"result": false
},
{
"type": "computedUserset",
"relation": "editor",
"result": false
},
{
"type": "computedUserset",
"relation": "owner",
"result": true,
"children": [
{
"type": "this",
"relation": "owner",
"result": true,
"tupleFound": "document:readme#owner@user:alice"
}
]
}
]
}
}
}Der Auflösungsbaum zeigt: Alice ist kein direkter viewer und kein editor, aber sie ist ein owner, und die viewer-Relation enthält or owner, daher besteht die Prüfung.
Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NO_ACTIVE_MODEL | 400 | Kein aktives Autorisierungsmodell |
INVALID_TYPE | 400 | Objekttyp existiert nicht im aktiven Modell |
INVALID_RELATION | 400 | Relation existiert nicht auf dem angegebenen Typ |
MAX_DEPTH_EXCEEDED | 400 | Auswertung hat die maximale Rekursionstiefe von 25 überschritten |
VALIDATION_ERROR | 400 | Fehlende Pflichtfelder |
In der Produktion sollten Ressourcenserver den Check-Endpunkt mit einem M2M-Token mit debug:fga aufrufen, anstatt ihn Endbenutzern zugänglich zu machen. Der explain-Modus ist besonders nützlich während der Entwicklung und beim Debuggen, verursacht aber Overhead und sollte in kritischen Pfaden deaktiviert werden.
Expand
/api/fga/expandRequires: debug:fgaEine Relation auf einem Objekt erweitern, um alle Subjekte zu entdecken, die diese Relation haben. Gibt eine Baumstruktur zurück, die den Umschreibungsregeln folgt und sowohl direkte Tupelzuweisungen als auch indirekte Beziehungen zeigt (Computed Usersets, Tuple-to-Userset).
Anforderungs-Body
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer"
}| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
objectType | string | Ja | Der Typ des Zielobjekts |
objectId | string | Ja | Die ID des Zielobjekts |
relation | string | Ja | Die zu erweiternde Relation |
Erfolgsantwort
{
"ok": true,
"data": {
"tree": {
"root": {
"type": "union",
"relation": "viewer",
"nodes": [
{
"type": "leaf",
"relation": "viewer",
"subjects": [
{ "type": "user", "id": "dave" },
{ "type": "user", "id": "eve" }
]
},
{
"type": "computedUserset",
"relation": "editor",
"subjects": [
{ "type": "user", "id": "bob" }
]
},
{
"type": "computedUserset",
"relation": "owner",
"subjects": [
{ "type": "user", "id": "alice" }
]
}
]
}
}
}
}Dies zeigt, dass document:readme folgende Viewer hat: Dave und Eve (direkt), Bob (über editor) und Alice (über owner).
Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NO_ACTIVE_MODEL | 400 | Kein aktives Autorisierungsmodell |
INVALID_TYPE | 400 | Objekttyp nicht im Modell gefunden |
INVALID_RELATION | 400 | Relation nicht auf diesem Typ gefunden |
Objekte auflisten
/api/fga/list-objectsRequires: debug:fgaAlle Objekte eines bestimmten Typs auflisten, auf die ein Subjekt über eine bestimmte Relation zugreifen kann. Führt einen Reverse-Lookup durch den Tupel-Speicher und die Umschreibungsregeln durch. Nützlich für den Aufbau gefilterter Ansichten wie “zeige mir alle Dokumente, die dieser Benutzer ansehen kann”.
Anforderungs-Body
{
"objectType": "document",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice"
}| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
objectType | string | Ja | Der Typ der zu suchenden Objekte |
relation | string | Ja | Die Relation, die das Subjekt haben muss |
subjectType | string | Ja | Der Typ des Subjekts |
subjectId | string | Ja | Die ID des Subjekts |
page | integer | Nein | Seitennummer für Paginierung (Standard: 1) |
limit | integer | Nein | Elemente pro Seite (Standard: 100, max: 1000) |
Erfolgsantwort
{
"ok": true,
"data": {
"objectIds": ["readme", "api-spec", "changelog", "roadmap"],
"total": 4
}
}Fehlercodes
| Code | HTTP | Beschreibung |
|---|---|---|
NO_ACTIVE_MODEL | 400 | Kein aktives Autorisierungsmodell |
INVALID_TYPE | 400 | Objekttyp nicht im Modell gefunden |
INVALID_RELATION | 400 | Relation nicht auf diesem Typ gefunden |
Die list-objects-Abfrage kann bei großen Tupel-Speichern aufwändig sein, da sie mehrere Tupel durchsuchen und auswerten muss. Verwende Paginierung und erwäge, Ergebnisse für häufig abgerufene Muster zwischenzuspeichern.
Berechtigungsreferenz
| Berechtigung | Beschreibung |
|---|---|
view:fga_models | Autorisierungsmodelle und ihre DSL-Definitionen anzeigen |
manage:fga_models | Autorisierungsmodelle erstellen, aktualisieren, löschen und aktivieren |
view:fga_tuples | Beziehungs-Tupel auflisten und lesen |
manage:fga_tuples | Beziehungs-Tupel schreiben und löschen (einzeln und in Bulk) |
debug:fga | Check-, Expand- und List-Objects-Abfragen ausführen |
Vollständiges Beispiel
Diese Schritt-für-Schritt-Anleitung demonstriert ein gängiges Autorisierungsmuster: ein teambasiertes Dokumentzugangssystem.
Schritt 1: Modell erstellen
POST /api/fga/models
{
"name": "Team-Dokumente",
"dsl": "type user\n\ntype team\n relations\n define member: [user]\n define admin: [user]\n\ntype document\n relations\n define owner: [user]\n define team: [team]\n define editor: [user, team#admin]\n define viewer: [user, team#member] or editor or owner\n"
}Schritt 2: Modell aktivieren
POST /api/fga/models/{modelId}/activateSchritt 3: Tupel schreiben
POST /api/fga/tuples/bulk
{
"writes": [
{ "objectType": "team", "objectId": "engineering", "relation": "member", "subjectType": "user", "subjectId": "alice" },
{ "objectType": "team", "objectId": "engineering", "relation": "member", "subjectType": "user", "subjectId": "bob" },
{ "objectType": "team", "objectId": "engineering", "relation": "admin", "subjectType": "user", "subjectId": "alice" },
{ "objectType": "document", "objectId": "arch-doc", "relation": "team", "subjectType": "team", "subjectId": "engineering" },
{ "objectType": "document", "objectId": "arch-doc", "relation": "editor", "subjectType": "team", "subjectId": "engineering", "subjectRelation": "admin" },
{ "objectType": "document", "objectId": "arch-doc", "relation": "viewer", "subjectType": "team", "subjectId": "engineering", "subjectRelation": "member" }
]
}Schritt 4: Zugang prüfen
POST /api/fga/check
{
"objectType": "document",
"objectId": "arch-doc",
"relation": "editor",
"subjectType": "user",
"subjectId": "alice",
"explain": true
}
// Ergebnis: { "allowed": true } — Alice ist ein Admin von engineering, was editor gewährtPOST /api/fga/check
{
"objectType": "document",
"objectId": "arch-doc",
"relation": "editor",
"subjectType": "user",
"subjectId": "bob"
}
// Ergebnis: { "allowed": false } — Bob ist ein Mitglied, aber kein AdminSchritt 5: Objekte auflisten, die ein Benutzer ansehen kann
POST /api/fga/list-objects
{
"objectType": "document",
"relation": "viewer",
"subjectType": "user",
"subjectId": "bob"
}
// Ergebnis: { "objectIds": ["arch-doc"] } — Bob kann über Teammitgliedschaft ansehenZugehörige Referenzen
- FGA / Zanzibar-Modell — Wie das Autorisierungsmodell und Umschreibungsregeln funktionieren
- Feingranulare Autorisierung Leitfaden — Praktische Anleitung zur FGA-Implementierung
- FGA-Debugger — Checks testen und Auflösungsbäume in der Konsole inspizieren
- Rollen & Berechtigungen API — RBAC-Endpunkte, die FGA ergänzen
- JavaScript SDK —
client.fga.check()und Tupelverwaltung aus dem SDK