如何在PostgreSQL中创建只读用户?

How do you create a read-only user in PostgreSQL?

我想在PostgreSQL中创建一个只能从特定数据库中进行选择的用户。在mysql中,命令是:

1
GRANT SELECT ON mydb.* TO 'xxx'@'%' IDENTIFIED BY 'yyy';

PostgreSQL中的等效命令或一系列命令是什么?

我试过…

1
2
postgres=# CREATE ROLE xxx LOGIN PASSWORD 'yyy';
postgres=# GRANT SELECT ON DATABASE mydb TO xxx;

但在数据库上,您只能授予create、connect、temporary和temp。


向单个表授予使用/选择权限

如果只授予连接到数据库的权限,则用户可以连接,但没有其他权限。您必须在名称空间(模式)上授予使用权限,并在表和视图上分别进行选择,如下所示:

1
2
3
4
GRANT CONNECT ON DATABASE mydb TO xxx;
-- This assumes you're actually connected to mydb..
GRANT USAGE ON SCHEMA public TO xxx;
GRANT SELECT ON mytable TO xxx;

多个表/视图(PostgreSQL 9.0+)

在最新版本的PostgreSQL中,您可以使用单个命令授予模式中所有表/视图/etc的权限,而不必逐个键入它们:

1
GRANT SELECT ON ALL TABLES IN SCHEMA public TO xxx;

这只影响已经创建的表。更强大的是,您可以在将来自动将默认角色分配给新对象:

1
2
ALTER DEFAULT PRIVILEGES IN SCHEMA public
   GRANT SELECT ON TABLES TO xxx;

注意,默认情况下,这只会影响由发出此命令的用户创建的对象(表):尽管它也可以设置在发出用户所属的任何角色上。但是,在创建新对象时,您不会为您所属的所有角色获取默认权限…所以仍然有一些虚伪。如果采用数据库具有所属角色的方法,并且模式更改作为该所属角色执行,则应将默认权限分配给该所属角色。imho这一切都有点令人困惑,您可能需要进行实验,才能想出一个功能性的工作流。

多个表/视图(9.0之前的PostgreSQL版本)

为了避免长时间、多表更改中的错误,建议使用以下"自动"过程为每个表/视图生成所需的GRANT SELECT

1
2
3
SELECT 'GRANT SELECT ON ' || relname || ' TO xxx;'
FROM pg_class JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE nspname = 'public' AND relkind IN ('r', 'v', 'S');

这应该输出相关的GRANT命令,以在公共的所有表、视图和序列上授予SELECT,以便进行复制粘贴操作。当然,这只适用于已经创建的表。


请注意,PostgreSQL 9.0(现在是beta测试版)将有一个简单的方法:

1
2
test=> GRANT SELECT ON ALL TABLES IN SCHEMA public TO joeuser;
GRANT


以下是我找到的添加只读用户的最佳方法(使用PostgreSQL 9.0或更高版本):

1
2
3
$ sudo -upostgres psql postgres
postgres=# CREATE ROLE readonly WITH LOGIN ENCRYPTED PASSWORD '<USE_A_NICE_STRONG_PASSWORD_PLEASE';
postgres=# GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;

然后登录到所有相关的机器(master+read slave(s)/hot standby(s)等)并运行:

1
2
$ echo"hostssl <PUT_DBNAME_HERE> <PUT_READONLY_USERNAME_HERE> 0.0.0.0/0 md5" | sudo tee -a /etc/postgresql/9.2/main/pg_hba.conf
$ sudo service postgresql reload


引用自此日志:

创建只读用户的脚本:

1
2
CREATE ROLE Read_Only_User WITH LOGIN PASSWORD 'Test1234'
NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE NOREPLICATION VALID UNTIL 'infinity';

将权限分配给此只读用户:

1
2
3
4
GRANT CONNECT ON DATABASE YourDatabaseName TO Read_Only_User;
GRANT USAGE ON SCHEMA public TO Read_Only_User;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO Read_Only_User;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO Read_Only_User;


默认情况下,新用户将具有创建表的权限。如果计划创建只读用户,这可能不是您想要的。

要使用PostgreSQL 9.0+创建真正的只读用户,请运行以下步骤:

1
2
3
4
5
6
7
8
9
10
# This will prevent DEFAULT users FROM creating TABLES
REVOKE CREATE ON SCHEMA public FROM public;

# IF you want TO GRANT a WRITE USER permission TO CREATE TABLES
# note that superusers will always be able TO CREATE TABLES anyway
GRANT CREATE ON SCHEMA public TO writeuser;

# Now CREATE the read-ONLY USER
CREATE ROLE readonlyuser WITH LOGIN ENCRYPTED PASSWORD 'strongpassword';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonlyuser;

如果只读用户没有列出表的权限(即\d不返回任何结果),可能是因为您没有该模式的USAGE权限。USAGE是一种允许用户实际使用已分配的权限的权限。这有什么意义?我不确定。修复:

1
2
3
4
5
# You can either GRANT USAGE TO everyone
GRANT USAGE ON SCHEMA public TO public;

# OR GRANT it just TO your READ ONLY USER
GRANT USAGE ON SCHEMA public TO readonlyuser;

我已经为它创建了一个方便的脚本:pg_grant_read_to_db.sh。这个脚本将只读权限授予数据库架构中所有表、视图和序列的指定角色,并将其设置为默认值。


如果您的数据库在公共模式中,那么很容易(假设您已经创建了readonlyuser)。

1
2
3
4
5
6
db=> GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonlyuser;
GRANT
db=> GRANT CONNECT ON DATABASE mydatabase TO readonlyuser;
GRANT
db=> GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO readonlyuser;
GRANT

如果您的数据库正在使用customschema,请执行上述操作,但还要添加一个命令:

1
2
db=> ALTER USER readonlyuser SET search_path=customschema, public;
ALTER ROLE

我读过所有可能的解决方案,这些都是好的,如果你记得连接到数据库之前,你授予的东西;)无论如何感谢所有其他的解决方案!!!!

1
USER@server:~$ sudo su - postgres

创建psql用户:

1
2
3
4
5
postgres@server:~$ createuser --interactive
Enter name OF ROLE TO ADD: readonly
Shall the NEW ROLE be a superuser? (y/n) n
Shall the NEW ROLE be allowed TO CREATE DATABASES? (y/n) n
Shall the NEW ROLE be allowed TO CREATE more NEW roles? (y/n) n

启动psql cli并为创建的用户设置密码:

1
2
3
4
5
6
postgres@server:~$ psql
psql (10.6 (Ubuntu 10.6-0ubuntu0.18.04.1), server 9.5.14)
TYPE"help" FOR help.

postgres=# ALTER USER readonly WITH password 'readonly';
ALTER ROLE

连接到目标数据库:

1
2
3
postgres=# \c target_database
psql (10.6 (Ubuntu 10.6-0ubuntu0.18.04.1), server 9.5.14)
You are now connected TO DATABASE"target_database" AS USER"postgres".

授予所有需要的特权:

1
2
3
4
5
6
7
8
target_database=# GRANT CONNECT ON DATABASE target_database TO readonly;
GRANT

target_database=# GRANT USAGE ON SCHEMA public TO readonly ;
GRANT

target_database=# GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly ;
GRANT

更改目标db public shema的默认权限:

1
2
target_database=# ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly;
ALTER DEFAULT PRIVILEGES

不简单的方法是在数据库的每个表上授予select:

1
postgres=# GRANT SELECT ON db_name.table_name TO read_only_user;

您可以通过从数据库元数据生成GRANT语句来实现自动化。


取自为响应Despesz链接而发布的链接。

Postgres9.x似乎具有执行请求的功能。见数据库对象授权段落:

http://www.postgresql.org/docs/current/interactive/sql-grant.html

其中说:"在一个或多个模式中,还可以选择授予同一类型的所有对象特权。目前,只有表、序列和函数才支持此功能(但请注意,所有表都被视为包括视图和外部表)。"

本页还讨论角色的使用和称为"所有特权"的特权。

还提供了有关如何将Grant功能与SQL标准进行比较的信息。