一、基础定义
RLS 是数据库原生行粒度访问控制能力,区别于传统仅能控制整张表的 GRANT 表权限,可通过策略规则限制角色 / 会话只能看到、修改表中满足条件的行,所有 DML(SELECT/INSERT/UPDATE/DELETE)都会自动追加过滤条件,对上层应用透明执行。
主流支持数据库:PostgreSQL(9.5+,生态最完善)、SQL Server 2016+、CockroachDB、BigQuery;BI 工具(Tableau/Power BI)也有同名 RLS(报表行过滤)。
行业最常用场景:SaaS 多租户数据隔离。
二、核心原理(PostgreSQL 标准实现)
2.1 启用开关
-- 普通开启:表所有者/超级用户默认绕过RLS
ALTER TABLE 表名 ENABLE ROW LEVEL SECURITY;
-- 强制开启:所有人(含表主、超级用户)都受策略约束,生产推荐
ALTER TABLE 表名 FORCE ROW LEVEL SECURITY;
开启后若无任何策略,所有行全部不可访问(默认拒绝)
2.2 策略两大核心子句
| 子句 | 作用 | 生效操作 |
|---|---|---|
USING (条件) |
读过滤:匹配条件的行才可见、可删/改 |
SELECT / UPDATE / DELETE
|
WITH CHECK (条件) |
写校验:新增/更新后的行必须满足条件,否则直接报错 |
INSERT / UPDATE
|
2.3查询自动重写
用户写 SELECT * FROM orders; 数据库底层自动拼接策略条件:
SELECT * FROM orders WHERE tenant_id = 当前会话租户ID;
无论 ORM、原生 SQL、批量操作,无法绕过,解决应用层漏写过滤导致的数据泄露风险。
2.4 会话上下文传参
应用登录后设置会话变量,策略读取变量做隔离:
SET app.tenant_id = 10086; -- 会话级,连接销毁失效
current_setting('app.tenant_id') -- 策略内读取
三、策略语法与示例(多租户标准模板)
-- 1. 建租户订单表
CREATE TABLE orders (
id bigserial primary key,
tenant_id int not null, -- 租户标识
amount numeric
);
-- 2. 开启强制RLS
ALTER TABLE orders FORCE ROW LEVEL SECURITY;
-- 3. 创建全局隔离策略(所有角色、所有操作)
CREATE POLICY tenant_isolate ON orders
FOR ALL -- 作用于SELECT/INSERT/UPDATE/DELETE
TO PUBLIC -- 所有数据库角色生效
USING (tenant_id = current_setting('app.tenant_id')::int)
WITH CHECK (tenant_id = current_setting('app.tenant_id')::int);
效果:
- 查询:只能查到自己租户订单;
- 新增 / 修改:强制 tenant_id 等于当前租户,无法插入别人租户数据。
四、典型业务场景
1.SaaS 多租户隔离(最主流)
单表存储全部客户数据,靠tenant_id隔离,杜绝代码漏过滤导致跨租户数据泄露,Supabase、PostgREST 核心依赖 RLS。
2.用户私有数据隔离
订单、个人资料表:用户仅能读写自己user_id对应行,管理员放开全量权限。
3.部门 / 组织权限隔离
OA、HR 系统:员工仅查看本部门数据,高管全量可见。
4.自动软删除过滤
USING(deleted_at IS NULL),查询永久屏蔽已删除数据。
5.合规隐私管控(HIPAA/GDPR)
医疗、金融系统,数据库层强制限制敏感病历、交易数据访问范围,满足审计要求。
五、RLS 核心优势
- 安全兜底:控制下沉数据库,不依赖应用层代码,漏写 WHERE 也不会泄密;
- 统一规则:一套策略作用于所有入口(API、后台、报表、存储过程);
- 简化开发:ORM / 接口无需重复拼接租户过滤逻辑;
- 易维护:权限规则改 SQL 策略即可,不用全量改业务代码;
- 审计可控:所有数据访问强制走统一过滤规则,便于日志溯源。
六、缺点与生产注意事项
1. 性能损耗
每条查询附加过滤条件,大表必须给tenant_id/user_id建立索引;
复杂多表关联策略易触发全表扫描,避免嵌套 RLS 表(递归风险)。
2. 权限绕过风险(默认坑)
ENABLE RLS模式下表所有者、superuser 不受策略限制;多租户必须用FORCE ROW LEVEL SECURITY;
TRUNCATE、外键约束、表 DDL 操作不受 RLS 管控,需单独控制角色权限。
3. 连接池会话污染
连接池复用会话时,current_setting租户 ID 残留会导致串数据;
解决方案:每次请求结束重置会话变量,或使用连接池事务隔离。
4. 批量 / 统计查询限制
跨租户统计、全局报表需要单独创建超级只读角色,或单独开管理员策略。
七、补充:其他领域 RLS
BI 工具 RLS(Power BI/Tableau)
报表层面行过滤,不同登录用户查看数据集不同行,仅作用可视化,不控制底层数据库;通信领域 RLS
无线局域网 RLS(Radio Local System),极少和数据库 RLS 混淆。
八、与传统方案对比
| 方案 | 安全强度 | 维护成本 | 适用场景 |
|---|---|---|---|
应用层 WHERE 过滤 |
低(漏写即泄露) | 高,全接口重复编码 | 简单单体、无多租户 |
| 视图封装 | 中,可绕过基表 | 中,多视图难管理 | 简单权限隔离 |
| RLS 行级安全 | 极高,数据库强制拦截 | 低,统一策略 | SaaS 多租户、隐私合规系统 |
九、MySQL 支持RLS吗
MySQL(社区版 5.7 / 8.0、RDS/Aurora MySQL 兼容版)没有原生 RLS(Row-Level Security)Amazon Web。MySQL Enterprise 企业版:同样不提供内置 RLS。
MySQL 三种主流 “模拟 RLS” 方案(多租户场景):
方案 1:应用层强制拼接 tenant_id(最常用,生产首选)
方案 2:可更新视图 + WITH CHECK OPTION(数据库层模拟)
方案 3:存储过程封装所有 CRUD(强隔离但笨重)