Tenant-Topologie-API
GET /api/tenant-topology sagt einer Anwendung, welche der erlaubten Tenants des angemeldeten Benutzers unterhalb des Root-Tenants der Anwendung liegen, wie tief jeder liegt und ob er selbst Kinder hat.
Den Endpunkt gibt es, weil eine Anwendung ihre Tenants nicht lernen darf, indem sie mit dem Token des Benutzers die GraphQL- oder REST-Routen anderer Tenants aufruft: Das Tenant-Gate der Plattform-Services lehnt solche Aufrufe ab, sobald es durchgesetzt wird. Identity beantwortet die Frage stattdessen aus der eigenen Tenant-Registry. Die Sicht der Anwendung steht unter Welche Tenants darf meine App anbieten?. Angular-Anwendungen rufen den Endpunkt nicht selbst auf, sondern verwenden TenantTopologyService aus @meshmakers/shared-auth.
Anfrage
GET https://<identity-host>/api/tenant-topology?scope=<rootTenantId>
Authorization: Bearer <Access-Token des Benutzers>
| Teil | Beschreibung |
|---|---|
<identity-host> | Der Issuer des Benutzer-Tokens (der Identity Service). Die Route hat kein {tenantId}-Segment. |
scope (Query, Pflicht) | Der Root-Tenant der Anwendung, zum Beispiel acme-root. |
| Bearer-Token | Das Access-Token eines angemeldeten Benutzers. Das Token braucht den Scope octo_api (oder octo_api.read_only); eine Rolle ist nicht nötig. |
Nur Benutzer-Tokens werden akzeptiert. Ein Token aus dem Client-Credentials-Flow hat keinen Benutzer und damit keine erlaubten Tenants; es wird mit 403 abgelehnt.
Antwort
200 OK, application/json:
{
"scope": "acme-root",
"scopeHasChildren": true,
"tenants": [
{ "tenantId": "acme-plant-a", "depth": 1, "hasChildren": false },
{ "tenantId": "acme-group-b", "depth": 1, "hasChildren": true },
{ "tenantId": "acme-plant-b1", "depth": 2, "hasChildren": false }
]
}
| Feld | Typ | Beschreibung |
|---|---|---|
scope | string | Der angefragte Scope (getrimmt). |
scopeHasChildren | boolean | Der Root-Tenant hat mindestens einen Tenant unter sich. false zusammen mit einer leeren tenants-Liste ist der Legacy-Einzeltenant-Fall: Der Root-Tenant ist der Anwendungs-Tenant. |
tenants | array | Die Tenants unterhalb des Scopes, die der Benutzer verwenden darf. Enthält nie den Scope selbst. |
tenants[].tenantId | string | Id des Tenants. |
tenants[].depth | integer | Abstand zum Scope: 1 ist ein direktes Kind des Scopes, 2 ein Kind dieses Kindes usw. |
tenants[].hasChildren | boolean | Der Tenant hat selbst mindestens ein Kind. Die Kinder werden nur aufgelistet, wenn der Benutzer sie verwenden darf. |
Mehr wird nie zurückgegeben: kein Scope-Eintrag, kein Tenant außerhalb der erlaubten Tenants des Benutzers oder außerhalb des Teilbaums des Scopes, keine Eltern-Ids und keine Tenant-Daten.
Wer was sieht
Die Liste ist die Schnittmenge zweier Mengen:
- der Tenants aus dem Claim
allowed_tenantsdes Benutzer-Tokens und - der echten Nachfahren von
scopein der Tenant-Hierarchie.
Der Claim begrenzt nur, welche Fakten offengelegt werden (eine Tiefe und ein Flag über Tenants, in die sich der Benutzer ohnehin anmelden kann). Er ist ein Auswahlhinweis, keine Autorisierung: Jede Anfrage an einen Tenant prüft weiterhin der Service dieses Tenants.
scopeHasChildren wird nur wahrheitsgemäß gemeldet, wenn der Scope in den allowed_tenants des Benutzers steht oder die Liste nicht leer ist; sonst ist es false. Ein Scope, der nicht existiert, keine wohlgeformte Tenant-Id ist, keine für den Benutzer erlaubten Tenants hat oder zur Hierarchie eines anderen gehört, wird gleich beantwortet: 200 mit leerer Liste und scopeHasChildren: false. So verrät der Endpunkt nichts über Tenants, die den Aufrufer nichts angehen.
Statuscodes
| Status | Bedeutung |
|---|---|
200 | Topologie geliefert (möglicherweise leer, siehe oben). |
400 | Der Query-Parameter scope fehlt oder ist leer. |
401 | Kein Token, oder das Token ist ungültig oder abgelaufen. |
403 | Das Token ist ein Client-Credentials-Token (kein Benutzer), oder dem Benutzer-Token fehlt der Lese-Scope octo_api. |
429 | Rate-Limit für diesen Benutzer überschritten. Die Antwort enthält Retry-After: 60. |
503 | Die Tenant-Hierarchie konnte nicht vollständig gelesen werden. Der Endpunkt schlägt geschlossen fehl: Er liefert nie eine Teilliste. Später erneut versuchen. |
Ein Identity Service, der den Endpunkt noch nicht hat, antwortet für /api/tenant-topology nicht mit 404, sondern mit 200 und text/html (sein Single-Page-Application-Fallback). Clients müssen eine erfolgreiche Antwort, deren Content-Type nicht JSON ist, wie ein 404 behandeln: Die Topologie ist unbekannt. TenantTopologyService aus @meshmakers/shared-auth tut das.
Caching und Limits
- Identity cached die Topologie eines Scopes für etwa 45 Sekunden. Ein Tenant, der gerade angelegt oder verschoben wurde, kann daher bis zu etwa 45 Sekunden brauchen, bis er erscheint oder verschwindet.
- Das Rate-Limit gilt pro Benutzer (gleitendes Fenster von einer Minute, standardmäßig 60 Anfragen). Cachen Sie das Ergebnis in der Anwendung, statt den Endpunkt bei jedem Seitenaufruf abzufragen.
- Der Endpunkt ist aus dem Browser aufrufbar: Die CORS-Richtlinie von Identity erlaubt die Origins, die an den Clients der Tenants hinterlegt sind.
Keine Sicherheitsgrenze
Die Topologie entscheidet nur, was eine Anwendung in ihrer Tenant-Auswahl anbietet. Sie gewährt keinen Zugriff und ersetzt keine Prüfung: Die Backend-Services erzwingen bei jeder Anfrage den Tenant des Tokens und die Berechtigungen des Benutzers. Eine Anwendung darf einen Tenant in der Liste nicht als Zugriffsnachweis behandeln und einen fehlenden Tenant nicht als Grund, anderswo eine Prüfung auszulassen.