PostgreSQL多对多关联场景下通过RLS行级安全实现租户用户过滤
解决方案
原有策略失效核心原因
user表本身没有tenant_id字段,无法直接做等值匹配,租户关联关系存储在user_tenant中间表中,需要通过关联查询判断权限- 未开启
user表的行级安全总开关,即使创建了策略也不会生效 - 示例中
tenant表的id为整数类型,原有策略中强制转uuid会出现类型匹配错误
具体实现步骤
1. 开启user表的行级安全
首先执行命令开启表级RLS开关:
ALTER TABLE "user" ENABLE ROW LEVEL SECURITY; -- 如果需要超级用户/表所有者也受RLS管控,可执行强制开启命令 ALTER TABLE "user" FORCE ROW LEVEL SECURITY;
2. 创建正确的RLS策略
通过EXISTS子句关联user_tenant中间表做权限判断,这里默认你my_user.current_tenant存储的是tenant表的id值:
CREATE POLICY tenant_policy ON "user" USING ( EXISTS ( SELECT 1 FROM user_tenant WHERE user_tenant.user_id = "user".id AND user_tenant.tenant_id = current_setting('my_user.current_tenant')::integer ) );
如果你的my_user.current_tenant存储的是租户名称(比如t1),可以调整关联逻辑连tenant表做匹配:
CREATE POLICY tenant_policy ON "user" USING ( EXISTS ( SELECT 1 FROM user_tenant JOIN tenant ON tenant.id = user_tenant.tenant_id WHERE user_tenant.user_id = "user".id AND tenant.name = current_setting('my_user.current_tenant') ) );
3. 验证效果
设置当前会话的租户参数后查询即可:
-- 设置当前租户为t1(对应id为1) SET my_user.current_tenant = '1'; -- 查询user表,只会返回id为1、3的用户 SELECT * FROM "user";
注意事项
- 测试时请使用普通权限的数据库角色,超级用户默认绕过RLS管控,除非你开启了
FORCE ROW LEVEL SECURITY - 确保
current_setting返回值和关联字段的类型完全匹配,避免类型转换错误导致策略失效
内容的提问来源于stack exchange,提问作者piyush
相关产品推荐
相关产品推荐

