RBAC jest modelem policy biznesowej, a nie kolumną role
W B2B SaaS authorization staje się problemem domenowym, gdy jedna osoba może należeć do wielu organizations, mieć inne obowiązki w każdej z nich, działać na resources z różnym ownership i delegować pracę services lub AI. Pojedyncza kolumna role w rekordzie usera nie potrafi bezpiecznie reprezentować takiego modelu.
Zaczynamy od relacji actor–organization–resource. Authentication odpowiada, kto się zalogował. Authorization odpowiada, czy ten actor, w tym tenant context, może teraz wykonać konkretną akcję na konkretnym resource.
Modeluj primitives authorization jawnie
| Primitive | Cel | Przykład |
|---|---|---|
| User | Globalna identity człowieka | [email protected] |
| Organization | Tenant / business boundary | Acme Europe |
| Membership | Relacja usera z organization | Matt należy do Acme Europe |
| Role | Wygodny pakiet permissions | Billing manager |
| Permission | Trwała business action | invoice.refund |
| Resource rule | Ogranicza akcję do właściwych obiektów | Tylko facilities w assigned region |
| Audit event | Dowód privileged change | Kto zatwierdził refund i dlaczego |
Egzekwuj permissions przy każdej server-side action
Ukrywanie elementów frontend poprawia UX, ale nie jest zabezpieczeniem. Każda API mutation, server action, queue consumer i internal tool zmieniający protected state potrzebuje authorization przy execution boundary. Check powinien korzystać z server-derived identity i tenant context, a nie ufać dowolnemu organization ID przesłanemu przez klienta.
Dla reads stosuj scoped repository/query helpers, aby bezpieczna ścieżka była domyślna. Dla writes odczytaj target resource, potwierdź tenant/ownership boundary, oceń permission i dopiero wykonaj domain command.
Roles grupują permissions, a permissions opisują możliwości biznesowe
Nazwy roles różnią się między klientami. Permissions powinny być stabilne, ponieważ opisują to, co produkt potrafi: member.invite, booking.cancel, invoice.issue, asset.measurement.approve. Role typu „Manager” jest tenant-configurable zestawem takich capabilities.
Ułatwia to migrations. Nową funkcję można wprowadzić jako permission i świadomie przypisać do istniejących roles, zamiast automatycznie nadawać każdemu „adminowi” nową władzę.
Resource policy zmienia prosty RBAC w prawdziwe B2B authorization
Dwóch users może mieć order.update, ale jeden może edytować tylko zamówienia przypisanej placówki albo wyłącznie rekordy niezamknięte przez finanse. Resource-level policy może łączyć tenant, ownership, status, geography, assignment i contractual constraints z permission.
Reguły te trzymaj we wspólnych authorization/domain functions zamiast duplikować w controllerach. W przeciwnym razie web, mobile, background jobs i AI tools zaczną egzekwować różne polityki.
Service accounts i AI actors wymagają jawnej semantyki
Automation nie powinna podszywać się pod omnipotent admin. Service identity powinna mieć purpose, tenant scope i allowed capabilities. Gdy AI tool działa w imieniu usera, zachowaj obie identities: requesting human/session oraz executing system actor. Audit event powinien potrafić wyjaśnić obie.
To istotne dla agentic systems: semantycznie poprawna decyzja modelu nadal jest nieważna, jeśli underlying actor nie mógłby wykonać operacji.
Audytuj privileged changes z kontekstem before/after
Dla membership, role, billing, export, deletion i innych privileged actions zapisuj actor, tenant, permission, target, timestamp, correlation request/run i znaczącą zmianę stanu. Sensitive values można zredagować, ale audit record powinien pozwolić odtworzyć decyzję.
Audit nie zastępuje authorization. Jest evidence layer pozwalającą zrozumieć, jak protected state zmienił się po przejściu authorization gate.
Database controls mogą tworzyć defense in depth
Application authorization pozostaje główną warstwą policy, ale mechanizmy takie jak PostgreSQL Row-Level Security mogą dawać dodatkową izolację wybranym multi-tenant tables. RLS jest skuteczny, gdy tenant context jest niezawodnie ustawiany dla każdej transakcji, a privileged connections nie omijają nieświadomie policy.
Nie używaj RLS do ukrywania niejasnego domain model. Najpierw ustal ownership i authorization semantics, potem zdecyduj, gdzie database enforcement realnie zmniejsza ryzyko.
Negative-path tests są obowiązkowe
Testy authorization powinny udowadniać denial, nie tylko success. Testuj cross-tenant IDs, removed memberships, stale sessions, downgraded roles, resources przeniesione między scopes, queued jobs uruchamiane po utracie permissions i direct API calls omijające UI.
W Softech te wzorce są podstawą multi-tenant SaaS development i business web applications. Celem nie jest najbardziej skomplikowany policy engine, lecz na tyle jawny ownership model, by wszystkie interfejsy egzekwowały te same reguły.
Ścieżka migracji z prostych roles
- Oddziel global user identity od organization membership.
- Wprowadź stable permission keys dla high-value actions.
- Zmapuj obecne roles na permission sets bez zmiany UX.
- Scentralizuj server-side authorization helpers.
- Dodaj resource/ownership policy tam, gdzie role-only checks nie wystarczają.
- Wprowadź audit events dla privileged actions.
- Dodaj negative-path i cross-tenant regression tests.
