PostgreSQL中常规视图读取调用者视图的权限逻辑问询
PostgreSQL嵌套视图中
security_invoker的角色切换逻辑解析 在PostgreSQL中,当常规视图嵌套调用security_invoker=true的视图时,角色权限的传递逻辑容易产生误解。本文结合测试场景解析其底层规则:
核心权限执行规则
- 常规视图(未设置
security_invoker):执行视图定义的查询时,会切换到视图所有者的角色权限,以此身份访问底层对象。 security_invoker=true的视图:执行视图定义的查询时,始终使用原始调用者的角色权限,不受任何上层视图的所有者身份影响——这是关键的规则差异。
测试场景验证
场景1:security_invoker视图调用常规视图
当带security_invoker=true的视图A查询常规视图B时:
- 视图A以调用者权限执行;
- 视图B作为常规视图,执行自身查询时切换到B的所有者权限,因此调用者看到的是B所有者权限下的内容,符合预期。
场景2:常规视图调用security_invoker视图
当常规视图C查询security_invoker=true的视图D时:
- 视图C执行时确实会切换到C的所有者权限;
- 但视图D是
security_invoker=true,它会忽略上层的C所有者身份,直接使用原始调用者的权限执行自身查询,因此最终结果是调用者自身权限下的内容,而非C所有者权限——这就是与预期不符的原因。
测试代码
CREATE SCHEMA test_views; SET search_path TO test_views; CREATE ROLE emplo; CREATE ROLE manager; GRANT usage ON SCHEMA test_views TO emplo, manager; GRANT CREATE ON SCHEMA test_views TO manager; CREATE TABLE test_views.employees ( id SERIAL PRIMARY KEY, name VARCHAR(100), department VARCHAR(100), salary NUMERIC ); INSERT INTO test_views.employees (name, department, salary) SELECT 'Employee ' || (RANDOM() * 100) :: INT, CASE WHEN RANDOM() < 0.5 THEN 'IT' ELSE 'HR' END, (RANDOM() * 100000) :: NUMERIC FROM generate_series(1, 1000); ALTER TABLE test_views.employees ENABLE ROW LEVEL SECURITY; CREATE POLICY emplo_hr_policy ON test_views.employees FOR SELECT USING (department = 'HR'); CREATE POLICY manager_all_policy ON test_views.employees FOR SELECT TO manager USING (TRUE); GRANT INSERT ON test_views.employees TO manager; GRANT SELECT ON test_views.employees TO emplo, manager; GRANT usage ON SEQUENCE test_views."employees_id_seq" TO manager; SET ROLE TO manager; -- 创建带security_invoker的视图 CREATE OR REPLACE VIEW test_views.invoker_view WITH (security_invoker = TRUE) AS SELECT * FROM employees; -- 创建调用invoker_view的常规视图 CREATE OR REPLACE VIEW test_views.leader_view AS SELECT * FROM invoker_view; -- 创建常规视图 CREATE OR REPLACE VIEW test_views.normal_view AS SELECT * FROM employees; -- 创建调用常规视图的security_invoker视图 CREATE OR REPLACE VIEW test_views.invoker_view_2 WITH (security_invoker = TRUE) AS SELECT * FROM normal_view; GRANT SELECT ON test_views.invoker_view, test_views.leader_view, test_views.normal_view, test_views.invoker_view_2 TO emplo, manager;
测试查询与结果解析
select current_role; set role to emplo; select * from test_views.invoker_view; -- 以调用者emplo权限执行,仅看到HR部门数据 select * from test_views.leader_view; -- 常规视图leader_view切换到manager权限,但invoker_view强制使用原始调用者emplo权限,最终仅看到HR部门数据 select * from test_views.normal_view; -- 常规视图以所有者manager权限执行,看到所有部门数据 select * from test_views.invoker_view_2; -- invoker_view_2以调用者emplo权限执行,调用normal_view时切换到manager权限,最终看到所有部门数据
内容的提问来源于stack exchange,提问作者pink_daemon
相关产品推荐
相关产品推荐

