
直接回答:SQL 视图本身不绕过 RLS,也不自动继承 RLS —— 启用 RLS 的基表上建的视图,查询时仍受基表策略约束;但若视图定义中硬编码了过滤条件(如 WHERE user_id = 123),它可能掩盖 RLS 策略的真实行为,导致权限逻辑混乱甚至失效。真正安全的做法是「不用视图替代 RLS」,而是让视图作为查询入口,RLS 在基表上独立生效。
视图查询仍触发基表 RLS 策略
PostgreSQL 中,对启用了 RLS 的表所创建的视图(无论是否带 WHERE),执行 SELECT 时仍会完整评估基表上的所有策略。视图只是重写查询的语法糖,不改变权限检查时机或层级。
- 例如:
CREATE VIEW user_data_v AS SELECT * FROM app_data;,用户查user_data_v时,PostgreSQL 实际执行的是SELECT * FROM app_data WHERE tenant_id = current_setting('app.tenant_id')::UUID(假设有对应策略) - 如果基表没启用 RLS,视图再怎么加
WHERE也无法提供真实行级隔离 —— 应用可绕过视图直查基表 -
pg_policies查到的策略只关联到基表,视图无独立策略存储
不要在视图里写“伪过滤”替代 RLS
常见错误是建一个看似安全的视图,比如:CREATE VIEW my_data AS SELECT * FROM app_data WHERE user_id = current_user_id();,然后给用户只授视图权限。这看起来像隔离,实则危险:
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
-
current_user_id()若未声明为LEAKPROOF,可能被策略引擎拒绝调用,导致视图报错或返回空 - 视图定义不可动态响应会话变量变更(如
current_setting('app.tenant_id')),除非函数显式标记STABLE或VOLATILE - 用户只要拿到基表
SELECT权限,就能绕过视图直接查全量数据 —— 视图不是访问控制层 - DBA 无法通过
\dp+或pg_policies审计这类“软隔离”,容易误判权限状态
视图 + RLS 的合理协作方式
视图应作为简化查询的工具,RLS 才是真正的守门人。两者配合的关键是「解耦职责」:视图负责字段投影/连接/计算,RLS 负责行过滤。
- 推荐写法:
CREATE VIEW user_profile_v AS SELECT id, name, email, created_at FROM app_users;(不带任何WHERE) - 确保
app_users已启用 RLS,并有类似CREATE POLICY user_view_policy ON app_users FOR SELECT USING (user_id = current_setting('app.user_id')::INT)的策略 - 给应用角色只授视图
SELECT权限,同时确保其对基表只有 RLS 允许的最小权限(如不授INSERT到基表,除非策略允许) - 测试时务必用目标角色连接,执行
EXPLAIN (VERBOSE) SELECT * FROM user_profile_v;,确认执行计划中包含 RLS 过滤条件
最容易被忽略的一点:RLS 策略中的表达式(尤其是涉及 current_setting() 或自定义函数)必须能在策略上下文中安全求值 —— 函数需标记 LEAKPROOF,会话变量必须提前由应用设置好,否则策略静默失效或报错中断查询。

















