使用行级安全实现租户隔离
PostgreSQL安全命令
ALTER TABLE app.orders ENABLE ROW LEVEL SECURITY;
-- Make the table owner subject to the policy too
ALTER TABLE app.orders FORCE ROW LEVEL SECURITY;
CREATE POLICY orders_tenant_isolation ON app.orders
FOR ALL
TO app_readwrite
USING (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::int)
WITH CHECK (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::int);
-- The application sets the tenant at the start of every transaction (pooler-friendly)
BEGIN;
SET LOCAL app.tenant_id = '42';
SELECT * FROM app.orders;
COMMIT;
-- Configured policies
SELECT schemaname, tablename, policyname, roles, cmd, qual, with_check
FROM pg_policies
WHERE tablename = 'orders';作用
在表上启用 RLS,并定义一个策略:按会话变量中的租户 id 过滤行(USING),并阻止写入其他租户的数据(WITH CHECK)。
适用场景
用于在数据库中为多租户应用强制实施数据隔离,而不是依赖应用代码。
注意
超级用户和具有 BYPASSRLS 属性的角色总是绕过策略;表所有者只有在 FORCE ROW LEVEL SECURITY 时才受其约束。启用 RLS 但没有匹配的策略时,结果为空(不报错)。变量未定义时 current_setting(..., true) 返回 NULL;NULLIF 可防止 RESET 后留下的空字符串因 ''::int 而失败。用户可以用 SET 修改 app.tenant_id;只能由受信任的应用层设置,终端用户不得获得 SQL 访问权限。使用 transaction 模式的连接池时,请用 SET LOCAL 代替 SET。为策略中使用的 tenant_id 列建立索引。以受 RLS 约束的用户运行 pg_dump 会失败;请用 BYPASSRLS 角色进行备份。