You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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. 可选:授权序列权限(针对自增字段)

如果你的表使用了serialidentity自增列,只读用户可能需要查看序列的当前值,这时候可以批量授权序列的USAGESELECT权限:

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

火山引擎 最新活动