Pau*_*aul 2 postgresql privileges information-schema
介绍
我一直在开发一个向导,为没有任何编程/SQL 背景的用户创建复杂的数据库 Postgres 查询。由于存储在 information_schema 视图中的外键约束,用户可以选择任意数量的表,并且该工具将找到正确的联接设置(因此,用户不必添加ON table_a.field_1 = table_b.field_2)。
在开发过程中,我一直使用管理数据库用户,现在想将其更改为只读用户以使其更安全。但是,这个只读用户似乎无法访问外键约束。
现在的情况
当选择了多个表时,该工具会尝试获取各个表之间的连接,以便了解如何连接它们。在此过程中,将执行以下查询:
SELECT
tc.constraint_name,
tc.table_name,
kcu.column_name,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY'
AND ccu.table_name = 'TableB'
AND tc.table_name IN ('TableA');
Run Code Online (Sandbox Code Playgroud)
WHERE(注意:使用最后一个子句IN是因为可以有多个可用基表。TableA 是基表,每个成功连接/联接的表将可用于其他联接,例如可以使用第三个表,AND ccu.table_name = 'TableC' AND tc.table_name IN ('TableA', 'TableB');依此类推。)
当使用 admin db 用户(具有最常见的权限,如 GRANT、SELECT、INSERT、UPDATE、DELETE、TRUNCATE...)执行查询时,结果如下所示:
constraint_name | table_name | column_name | foreign_table_name | foreign_column_name
----------------+------------+-------------+--------------------+---------------------
constraint1 | TableA | field_1 | TableB | field_2
(1 row)
Run Code Online (Sandbox Code Playgroud)
但是当只读数据库用户运行该查询时,它会返回:
constraint_name | table_name | column_name | foreign_table_name | foreign_column_name
----------------+------------+-------------+--------------------+---------------------
(0 rows)
Run Code Online (Sandbox Code Playgroud)
由于存在但未返回的外键约束条目,连接无法正确编写为 SQL,并且用户生成的查询(通过使用向导)失败。
我尝试过的
首先,我当然认为只读用户(ro_user)可能没有访问数据库中的表和视图的权限information_schema。所以我跑了
GRANT SELECT ON ALL TABLES IN SCHEMA information_schema TO ro_user;
Run Code Online (Sandbox Code Playgroud)
作为管理员但无济于事。更深入地了解文档,我发现information_schema在 postgres 中默认情况下任何用户都可以使用和访问其中的所有表和视图。因此,授予选择权限甚至不应该改变任何东西。
为了确定一下,我也跑了
GRANT REFERENCES ON ALL TABLES IN SCHEMA actual_database TO ro_user;
Run Code Online (Sandbox Code Playgroud)
但当然,这也没有改变任何东西,因为REFERENCES只需要创建新的外键,我只需要阅读它们。
接下来,我想,也许该工具的 sql 由于某些信息不可用而失败,因此我通过运行分别查询三个视图:
SELECT * FROM information_schema.table_constraints AS tc WHERE constraint_type = 'FOREIGN KEY';
SELECT * FROM information_schema.key_column_usage AS kcu;
SELECT * FROM information_schema.constraint_column_usage AS ccu;
Run Code Online (Sandbox Code Playgroud)
果然,最后一个不会为 ro_user 返回任何一行:
psql=> SELECT * FROM information_schema.constraint_column_usage AS ccu;
table_catalog | table_schema | table_name | column_name | constraint_catalog | constraint_schema | constraint_name
---------------+--------------+------------+-------------+--------------------+-------------------+-----------------
(0 rows)
Run Code Online (Sandbox Code Playgroud)
而管理员用户得到了很多结果。所以,一切都归结为这一观点information_schema.constraint_column_usage。
当我在一个小时的时间里打出这个问题时,回忆并总结了我在过去几天尝试过的所有想法,我终于找到了原因。
视图constraint_column_usage标识当前数据库中某些约束使用的所有列。仅显示当前启用的角色所拥有的表中包含的那些列。
通过这个我找到了一个解决方案
SELECT
conrelid::regclass AS table_from,
conname,
pg_get_constraintdef(c.oid) AS cdef
FROM pg_constraint c
JOIN pg_namespace n
ON n.oid = c.connamespace
WHERE contype IN ('f')
AND n.nspname = 'public'
AND pg_get_constraintdef(c.oid) LIKE '%"TableB"%'
AND conrelid::regclass::text IN ('"TableA"')
ORDER BY conrelid::regclass::text, contype DESC;
Run Code Online (Sandbox Code Playgroud)
它不会输出与旧查询相同的格式,但它包含相同的信息,并且最重要的是可供 ro_user 使用。
| 归档时间: |
|
| 查看次数: |
7410 次 |
| 最近记录: |