如何在PostgreSQL中为所有模式创建只读用户?
批量创建PostgreSQL全模式表的只读用户
当然有高效的办法!不用手动给60多个模式重复执行命令,我们可以借助PostgreSQL的系统视图+动态SQL来一键完成批量授权操作。下面是详细步骤:
1. 先创建只读用户
首先创建一个专门的只读用户,确保它没有超管或创建权限,保证安全性:
CREATE USER readonly_user WITH PASSWORD 'your_strong_password' NOSUPERUSER NOCREATEDB NOCREATEROLE LOGIN;
NOSUPERUSER/NOCREATEDB/NOCREATEROLE:限制用户权限,避免越权操作LOGIN:允许用户登录数据库
2. 批量授权所有自定义模式的USAGE权限
要访问模式内的表,用户首先需要拥有该模式的USAGE权限。我们通过查询系统视图pg_namespace过滤掉系统模式(如pg_开头、information_schema),自动生成授权语句:
DO $$ DECLARE schema_rec record; BEGIN -- 遍历所有非系统模式 FOR schema_rec IN SELECT nspname FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema' LOOP -- 为每个模式授权USAGE EXECUTE 'GRANT USAGE ON SCHEMA ' || quote_ident(schema_rec.nspname) || ' TO readonly_user;'; END LOOP; END $$;
quote_ident():用来处理带特殊字符或关键字的模式名,避免语法错误或注入风险
3. 批量授权所有表的SELECT权限
接下来给所有非系统表授权SELECT权限,通过关联pg_class(存储表信息)和pg_namespace来获取所有自定义表:
DO $$ DECLARE table_rec record; BEGIN FOR table_rec IN SELECT n.nspname AS schema_name, c.relname AS table_name FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid WHERE c.relkind = 'r' -- 仅匹配普通表(如果要包含视图,改成c.relkind IN ('r', 'v')) AND n.nspname NOT LIKE 'pg_%' AND n.nspname != 'information_schema' LOOP EXECUTE 'GRANT SELECT ON TABLE ' || quote_ident(table_rec.schema_name) || '.' || quote_ident(table_rec.table_name) || ' TO readonly_user;'; END LOOP; END $$;
如果你的业务需要让只读用户能查看视图,只需把c.relkind = 'r'改成c.relkind IN ('r', 'v')即可。
4. 可选:授权序列权限(针对自增字段)
如果你的表使用了serial或identity自增列,只读用户可能需要查看序列的当前值,这时候可以批量授权序列的USAGE和SELECT权限:
DO $$ DECLARE seq_rec record; BEGIN FOR seq_rec IN SELECT n.nspname AS schema_name, c.relname AS seq_name FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid WHERE c.relkind = 'S' -- 匹配序列 AND n.nspname NOT LIKE 'pg_%' AND n.nspname != 'information_schema' LOOP EXECUTE 'GRANT USAGE, SELECT ON SEQUENCE ' || quote_ident(seq_rec.schema_name) || '.' || quote_ident(seq_rec.seq_name) || ' TO readonly_user;'; END LOOP; END $$;
注意事项
- 执行以上脚本需要用超级用户或拥有对应模式/表权限的用户登录
- 以上操作仅对现有模式和表生效,如果之后新建模式/表,需要重新执行脚本,或者提前设置默认权限:
若要给所有未来新建的模式设置默认权限,可能需要结合触发器或自动化脚本,不过一般日常运维中,新建模式后重新执行一次批量授权脚本就足够了。-- 示例:给public模式的新建表默认授权SELECT ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_user;
验证权限
可以切换到只读用户,尝试查询任意表,或者用以下SQL验证特定表的权限:
SELECT has_table_privilege('readonly_user', 'your_schema.your_table', 'select');
返回t则表示权限已正确授予。
内容的提问来源于stack exchange,提问作者purplefloyd




