PostgreSQL行级安全(会话变量)策略未生效问题排查
为什么PostgreSQL行级安全策略没生效?
你遇到的这个问题其实是PostgreSQL RLS(行级安全)的一个默认行为导致的,咱们一步步拆解:
先还原你的场景
你已经完成了这些操作:
create table user_table ( username text, idx integer ); alter table user_table enable row level security; create policy user_p on user_table for select using (idx <= (current_setting('my.idx',true)::int)); insert into user_table values('1',1),('2',2),('3',3);
然后设置会话变量后查询,预期只返回idx ≤ 2的行,结果却拿到了全表数据:
# set my.idx = 2; SET # select * from user_table; username | idx ----------+----- 1 | 1 2 | 2 3 | 3 (3 rows)
核心原因:表所有者不受RLS约束
PostgreSQL有个默认规则:创建表的用户(表所有者)默认不受行级安全策略的限制。也就是说,哪怕你给表启用了RLS,只要你用所有者账号查询,策略会直接被忽略,能看到所有行。
显然,你当前操作的账号就是user_table的所有者,这就是策略没生效的根本原因。
解决办法:强制对所有者启用RLS
要让RLS规则也作用于表所有者,只需要在启用RLS的时候加上force选项就行。你可以修改之前的alter table语句:
-- 先启用RLS(如果已经做过可以跳过) alter table user_table enable row level security; -- 强制所有者也遵守RLS策略 alter table user_table force row level security;
或者合并成一步:
alter table user_table enable row level security force;
验证修改后的效果
重新执行你的测试步骤:
# set my.idx = 2; SET # select * from user_table; username | idx ----------+----- 1 | 1 2 | 2 (2 rows)
这次就会返回你预期的结果了。
额外测试思路:用普通用户验证
如果你不想修改RLS的强制设置,也可以切换到非所有者账号来测试RLS是否正常工作:
-- 创建一个普通测试用户 create user test_user with password 'test_pass'; -- 给这个用户查询权限 grant select on user_table to test_user; -- 切换到test_user身份 set role test_user; set my.idx = 2; select * from user_table; -- 只会返回前两行,策略生效
内容的提问来源于stack exchange,提问作者lin
相关产品推荐
相关产品推荐

