Коротка відповідь
Продукт перевіряє membership вибраного tenant і передає scope через усі операції. Tenant ID URL — вибір, не дозвіл. Спочатку scoped-запити й записи, потім shared tables, schemas чи databases за ізоляцією й підтримкою. Топологія не авторизує користувача.
Практичні кроки реалізації
1. Отримайте перевірений tenant context
Прочитайте сесію, tenant, активне membership і role та сформуйте внутрішній context. Client-header чи role не авторитетні. У користувача можуть бути різні дозволи кількох tenant. Перемикання явне, чутлива операція повторно перевіряє membership.
2. Обмежте весь граф даних
Tenant входить у читання, записи, унікальність і зв’язки. Глобальний ID не є доступом. Foreign key лише з ID може допускати міжtenant-зв’язок. Public-проєкція після scoped-read. Експорт, пошук, download і admin мають ту саму політику.
3. Передайте scope у фонову роботу й кеш
Job містить tenant і операцію, потім відновлює дозволений context. Cache-key включає tenant, теги лише групують інвалідацію. Storage-path потребує авторизації. Session-level tenant у pool небезпечний: потрібні transaction-local context і cleanup.
4. Додайте політики бази
PostgreSQL RLS обмежує рядки, але owner зазвичай обходить її, як superuser і BYPASSRLS. FORCE ROW LEVEL SECURITY підпорядковує owner політиці. Використовуйте відповідну app-role, перевірте read, write і missing context. Тест restricted-role не доводить deployed-owner.
Приклад реалізації
Builder показує tenant scope і параметри. Context створює серверна membership-перевірка, не сама назва типу. Приклад не виконує базу. Адаптер зв’язує values окремо й додає scope до мутацій, joins і зв’язків.
type VerifiedTenantContext = { tenantId: string; userId: string };
export function reportQuery(
context: VerifiedTenantContext, reportId: string,
) {
return {
text: "SELECT id, title FROM report WHERE tenant_id = $1 AND id = $2",
values: [context.tenantId, reportId],
};
}
Компроміси та альтернативи
Shared tables зменшують інфраструктуру, але підсилюють важливість scope. Окремі schemas/databases допомагають ізоляції й restore та додають міграції й provisioning. Вони не усувають дозволи чи помилковий вибір бази. Визначте tenant-restore, deletion й операційні межі.
Поширені помилки
Не авторизуйте selector, не покладайтеся на ID, не кешуйте без tenant, не забувайте exports. RLS не захищає bypass-role. Optional tenant у багатьох helper небезпечний: один unscoped-виклик може розкрити чужі записи.
Перевірка перед випуском
- Context походить із перевіреного membership.
- Читання, записи, joins і правила мають scope.
- Кеш, файли, exports і jobs містять tenant.
- Перевірки використовують app-role.
- Restore й deletion tenant описані.
Поширені запитання
Чи потрібна окрема база?
Ні. Вибирайте за ізоляцією й підтримкою. Авторизація й scope потрібні в обох.
Чи tenant-tag запобігає витоку?
Ні. Tag групує інвалідацію, ключ і дозволений reader визначають правильні дані.
Наступний крок
Простежте read, write, export і кеш для двох tenant із різними membership. Усуньте відсутній scope, перевірте реальну database-role й tenant-restore.
Первинні джерела
Пов’язані матеріали та приклади
Потрібно реалізувати це у вашому продукті?
Перегляньте відповідні приклади продуктів або поділіться контекстом розробки вебзастосунку, розширення Chrome, API чи SaaS.