PostgreSQL 数据库权限、角色总结
概述
学习如何配置、管理权限,至少需要掌握几个方面的内容:
- 数据库对象的权限的初始状态,以及权限类型、数据库对象的类型的对应关系。
- 角色属性、角色成员的配置,预定义角色,
create/alter/drop role
的使用。 grant
和revoke
的使用。- 常用于权限管理的表格与视图。
1、权限
(1)权限的初始状态
对象的所有者(或超级用户)可以对该对象执行任何操作。
ALTER TABLE table_name OWNER TO new_owner;
"owner to" 一个新的所有者。
(2)grant 和 revoke
使用 grant 和 revoke 进行授权和撤权。
grant 权限类型 on 适用对象 to 用户(组);
revoke 权限类型 on 适用对象 from 用户(组);
在 SQL 标准中,用户和角色为不同的概念;在 PostgreSQL 中,用户和角色统一为一种实体,即用户和角色是“相同的”,用户是具有连接登录权限的角色。
(3)权限类型
权限类型包括:SELECT、INSERT、UPDATE、DELETE、TRUNCATE、REFERENCES、TRIGGER、CREATE、CONNECT、TEMPORARY、EXECUTE、USAGE、SET、ALTER SYSTEM。
详情如下:
SELECT
- 允许从表、视图、具体化视图或其他类似表的对象的任何列或特定列执行 SELECT 操作。
- 还允许使用 COPY TO。
- UPDATE、DELETE 或 MERGE 也需要此权限。
- 对于 SEQUENCE,此权限还允许使用 currval 函数。
- 对于 LARGE OBJECT,此权限允许读取对象。
INSERT
- 允许将新行 INSERT 到表、视图等中。可以在特定列上授予,在这种情况下,只能在 INSERT 命令中使用这些列(其他列将获得默认值)。
- 还允许使用 COPY FROM。
UPDATE
- 允许对表、视图等的任何列或特定列执行 UPDATE。
- 对于 SEQUENCE,此权限允许使用 nextval 和 setval 函数。
- 对于 LARGE OBJECT,此权限允许写入或截断对象。
DELETE
允许从表、视图等中 DELETE 行。
TRUNCATE
允许对表进行 TRUNCATE。
REFERENCES
允许创建引用表的外键约束或表的特定列。
TRIGGER
允许在表、视图等上创建触发器。
CREATE
- 对于数据库,允许在数据库中创建新的 SCHEMA 和发布,并允许在数据库中安装 Trusted Extensions。
- 对于 SCHEMA,允许在 SCHEMA 中创建新对象。要重命名现有对象,您必须拥有该对象,并拥有此权限。
- 对于表空间,允许在表空间内创建表、索引和临时文件,并允许创建
将表空间作为其默认表空间
的数据库。
请注意,撤销此权限,不会更改现有对象的存在或位置(即不会删除对象)。
CONNECT
允许被授权者连接到数据库。在连接启动时检查此权限(除了检查 pg_hba.conf 施加的任何限制外)。
TEMPORARY
允许在使用数据库时创建临时表。
EXECUTE
允许调用函数或过程,包括使用在函数上实现的任何运算符。这是唯一适用于函数和过程的权限类型。
USAGE
- 对于过程语言(LANGUAGE),允许使用该语言创建函数。这是唯一适用于过程语言的权限类型。
- 对于 SCHEMA,允许访问 SCHEMA 中包含的对象(假设还满足对象自己的权限要求)。从本质上讲,这允许被授权者在 schema 中 “查找” 对象。如果没有此权限,仍然可以查看对象名称,例如,通过查询 system catalog。此外,撤销此权限后,现有会话可能具有以前执行过此 “查找” 的语句,因此这不是阻止对象访问的完全安全方法。
- 对于SEQUENCE,允许使用 currval 和 nextval 函数。
- 对于 DOMAIN 和 TYPE,允许在创建表、函数和其他架构对象时使用 DOMAIN 和 TYPE。此权限并不控制该类型的所有 “用法”,例如,查询中出现的 type 的值。它仅阻止创建依赖于 TYPE 的对象。此权限的主要目的是控制哪些用户可以创建对 TYPE 的依赖关系,这可能会阻止所有者以后更改类型。
- 对于 FOREIGN DATA WRAPPER,允许使用外部数据包装器创建新服务器。
- 对于 FOREIGN SERVER,允许使用服务器创建外部表。被授权者还可以创建、更改或删除与该服务器关联的用户映射。
SET
允许在当前会话中将服务器配置参数设置为新值。
ALTER SYSTEM
允许使用 ALTER SYSTEM 命令将服务器配置参数配置为新值。
另,需要特别注意的是,角色属性可以影响角色的权限,这些属性包括:是否为超级用户(SUPERUSER/NOSUPERUSER)、是否可以创建新角色(CREATEROLE/NOCREATEROLE)、是否可以启动流复制(REPLICATION/NOREPLICATION)、是否可以绕过行级安全性(BYPASSRLS/NOBYPASSRLS)、角色连接最大数量(CONNECTION LIMIT)。但这一般是在创建角色时,通过角色属性进行设置。
(4)适用对象的类型
权限及其适用的对象的类型:
权限类型 | 缩写 | 适用对象的类型 |
---|---|---|
SELECT | r (“read”) | LARGE OBJECT, SEQUENCE, TABLE (and table-like objects), table column |
INSERT | a (“append”) | TABLE, table column |
UPDATE | w (“write”) | LARGE OBJECT, SEQUENCE, TABLE, table column |
DELETE | d | TABLE |
TRUNCATE | D | TABLE |
REFERENCES | x | TABLE, table column |
TRIGGER | t | TABLE |
CREATE | C | DATABASE, SCHEMA, TABLESPACE |
CONNECT | c | DATABASE |
TEMPORARY | T | DATABASE |
EXECUTE | X | FUNCTION, PROCEDURE |
USAGE | U | DOMAIN, FOREIGN DATA WRAPPER, FOREIGN SERVER, LANGUAGE, SCHEMA, SEQUENCE, TYPE |
SET | s | PARAMETER |
ALTER SYSTEM | A | PARAMETER |
对象及其可以授予的权限:
对象的类型 | 权限 | 默认公开权限 | psql Command |
---|---|---|---|
DATABASE | CTc | Tc | \l |
DOMAIN | U | U | \dD+ |
FUNCTION or PROCEDURE | X | X | \df+ |
FOREIGN DATA WRAPPER | U | none | \dew+ |
FOREIGN SERVER | U | none | \des+ |
LANGUAGE | U | U | \dL+ |
LARGE OBJECT | rw | none | \dl+ |
PARAMETER | sA | none | \dconfig+ |
SCHEMA | UC | none | \dn+ |
SEQUENCE | rwU | none | \dp |
TABLE (and table-like objects) | arwdDxt | none | \dp |
Table column | arwx | none | \dp |
TABLESPACE | C | none | \db+ |
TYPE | U | U | \dT+ |
(5)默认情况
默认情况下,PostgreSQL 在创建对象时,不会将某些类型的对象的权限授予 PUBLIC:FOREIGN DATA WRAPPER、FOREIGN SERVER、LARGE OBJECT、PARAMETER、SCHEMA、SEQUENCE、TABLE 、Table column 及 TABLESPACE。
默认情况下,PostgreSQL 在创建对象时,会将某些类型的对象的权限授予 PUBLIC:DATABASE 【CONNECT 和 TEMPORARY(创建临时表)权限】,FUNCTION or PROCEDURE【EXECUTE 权限】,DOMAIN、LANGUAGE、TYPE【USAGE 权限】。当然,对象所有者可以 REVOKE 这些默认权限,并显式授予权限。为了获得最大的安全性,请在创建对象的同一事务中发出 REVOKE;然后,其他用户就不能使用该对象。
此外,还可以使用 ALTER DEFAULT PRIVILEGES 命令覆盖这些默认权限设置。
2、角色
(1)数据库角色
数据库角色在数据库集群安装中是全局的(而不是按单个数据库)。
新初始化的系统始终包含一个预定义的角色。此角色始终是“超级用户”,通常,此角色将命名为 postgres。
与数据库服务器的每个连接,都是使用某个特定角色的名称建立的,在该连接中,该角色确定初始访问权限。
特殊的 “角色” 名称 PUBLIC 可用于向系统上的每个角色授予权限。它自动地、隐式地包含了数据库中的每个用户。
任何特定角色都将具有:直接授予它的权限
、授予它当前所属的组角色的权限,以及授予 PUBLIC 的权限
。
(2)角色属性
LOGIN/NOLOGIN:
LOGIN:具有此属性的角色可以用于数据库连接,即可以视为登录用户。
NOLOGIN:没有此属性的角色不能用于数据库连接,默认值。
SUPERUSER/NOSUPERUSER:
SUPERUSER:超级用户拥有数据库的所有权限,包括创建数据库、创建角色、修改系统配置等。
NOSUPERUSER:非超级用户,其权限受到一定限制,默认值。
CREATEDB/NOCREATEDB:
CREATEDB:具有此属性的角色可以创建数据库。
NOCREATEDB:没有此属性的角色不能创建数据库,默认值。
CREATEROLE/NOCREATEROLE:
CREATEROLE:具有此属性的角色可以创建、修改和删除其他角色,以及给其他角色赋予或撤销权限。应将具有“创建角色”权限的用户,视为超级用户。
NOCREATEROLE:没有此属性的角色不能执行上述操作,默认值。
INHERIT/NOINHERIT:
INHERIT:具有此属性的角色会自动继承其所属组角色的权限,默认值。需要注意的是,角色属性 对应的权限并不被继承,例如,CREATEDB、CREATEROLE;即通过 create role 和 alter role 设置的角色属性,不被继承。但在 PostgreSQL 的早期版本中,会继承所有权限。被继承的,是诸如对表等对象的操作权限。另,需要注意的是,在 SQL 标准中,只有角色有继承属性,并且继承所有权限,而用户没有所谓的继承。
NOINHERIT:没有此属性的角色不会继承其所属组角色的权限,除非显式地执行SET ROLE命令来临时“成为”组角色。
REPLICATION/NOREPLICATION:
REPLICATION:具有此属性的角色可以启动流复制。
NOREPLICATION:没有此属性的角色不能启动流复制,默认值。
BYPASSRLS/NOBYPASSRLS:
BYPASSRLS:具有此属性的角色可以绕过行级安全性(Row-Level Security, RLS)检查【另,超级用用和所有者始终绕过 RLS 检查】。
NOBYPASSRLS:没有此属性的角色不能绕过RLS检查,默认值。
CONNECTION LIMIT:
此属性用于限制角色可以同时建立的连接数,但超级用户不受限。
PASSWORD:
用于设置角色的密码。如果设置了密码,则角色在连接数据库时需要提供该密码。
VALID UNTIL:
此属性用于设置角色的密码有效期。它仅定义密码的过期时间,而不是角色本身的过期时间。特别是,使用非基于密码的身份验证方法登录时,不会强制执行过期时间。
角色属性的运用
--CREATE:
CREATE ROLE name [ [ WITH ] option [ ... ] ];
/*
option 可以是一个或多个角色属性、参数:
SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit
| [ ENCRYPTED ] PASSWORD 'password' | PASSWORD NULL
| VALID UNTIL 'timestamp'
| IN ROLE role_name [, ...]
| IN GROUP role_name [, ...]
| ROLE role_name [, ...]
| ADMIN role_name [, ...]
| USER role_name [, ...]
| SYSID uid
其中,SYSID 仅用于向后兼容,将被忽略。
*/
--ALTER:
ALTER ROLE role_specification [ WITH ] option [ ... ];
/*
option 可以是一个或多个角色属性:
SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit
| [ ENCRYPTED ] PASSWORD 'password' | PASSWORD NULL
| VALID UNTIL 'timestamp'
*/
注意事项:
-
使用 ALTER ROLE 更改角色的属性,
使用 DROP ROLE 删除角色。
CREATE ROLE 指定的所有属性都可以由 ALTER ROLE 命令进行修改。- ALTER ROLE 语句是 PostgreSQL 扩展,在SQL标准中,并没有直接名为 ALTER ROLE 的子句。很多现代的数据库管理系统提供了相同的功能。
-
首选使用 GRANT 和 REVOKE 进行用户组的成员管理。
在 CREATE ROLE 时,可以立即指定 新建角色 属于哪个组或其包含哪些现有角色。- IN ROLE 或 IN GROUP:指定 新建角色 属于哪个组;
- ROLE 或 USER:指定 新建角色 包含哪些现有角色;
- ADMIN:同 ROLE【指定 新建角色 包含哪些现有角色】,但同时使 列出的现有角色具有以下权限:添加成员到该组。
(3)角色成员
将用户分组,以简化权限管理。
-
作为组的角色一般不具有 LOGIN 属性,但可以根据需要,设置该属性。
-
将作为组的角色视为一组权限,授予不同的角色,或从角色上撤销:
GRANT group_role TO role1, ... ;
REVOKE group_role FROM role1, ... ;
组角色
和非组角色
之间实际上没有任何区别。
授权不允许形成循环。
不允许向 PUBLIC 授予角色的成员资格,即不要向 public 组添加成员。它自动包含数据库中的每个用户。
成员角色
通过两种方式使用组角色
的权限:
- 成员角色都可以显式地执行 SET ROLE 来临时“成为”组角色。在此状态下,数据库会话可以访问组角色而不是原始登录角色的权限,并且创建的任何数据库对象都被视为由组角色而不是成员角色拥有。
- 其次,具有 INHERIT 属性的成员角色会自动使用其所属角色的权限,包括继承的任何权限。
举例说明:
--创建具有INHERIT属性的角色joe:
CREATE ROLE joe LOGIN INHERIT;
--创建具有NOINHERIT属性的角色admin:
CREATE ROLE admin NOINHERIT;
--创建具有NOINHERIT属性的角色wheel:
CREATE ROLE wheel NOINHERIT;
--将joe作为成员,添加进admin组:
GRANT admin TO joe;
--将admin作为成员,添加进wheel组:
GRANT wheel TO admin;
一个 session 以 joe 身份连接登录数据库,则立即具有授予 joe 的权限
和 授予 admin 的权限
。因为 joe 具有属性 INHERIT,能继承其所在组 admin 的任何权限。
即便 joe 也是 wheel 的成员(间接地),但该 session 并不具有授予 wheel 的权限
。因为 admin 具有属性 NOINHERIT,并未继承任何来自 wheel 的权限。
SET ROLE admin;
执行 SET ROLE admin;
之后,数据库将该 session 视为以 admin 连接,则仅具有授予 admin 的权限
。
SET ROLE wheel;
执行 SET ROLE wheel;
之后,数据库将该 session 视为以 wheel 连接,则仅具有授予 wheel 的权限
。
要想恢复到原始状态,执行以下任一语句即可:
SET ROLE joe;
SET ROLE NONE;
RESET ROLE;
注意事项一:
在 SQL 标准中,角色与用户有明显的区别,角色自动继承其所属组的权限,而用户不会。
在 PostgreSQL 要想达到同样效果,可以通过:
- 将角色的属性设置为 INHERIT,使角色像 SQL标准中的角色一样,能自动继承其所属组的权限;
- 将角色的属性设置为 NOINHERIT,使角色像 SQL标准中的用户一样,不能自动继承其所属组的权限。
注意事项二:
诸如 LOGIN
, SUPERUSER
, CREATEDB
和 CREATEROLE
等这些角色属性,视为不能被继承的权限。在上述的例子中,假定已经给 admin 设置了属性 CREATEDB
和 CREATEROLE
,以 joe 身份连接登录数据库的 session 并不能立即具有创建数据库和创建角色的权限,需要执行 SET ROLE admin;
之后才可以。
(4)drop 角色
删除一个角色,首先必须删除干净所有者是该角色的对象,或将这些对象改为其他角色所有;并且必须撤销授予该角色的任何权限。
可以使用 ALTER 命令来修改对象的所有者,例如,ALTER TABLE table_name OWNER TO new_owner;
也可以使用 REASSIGN OWNED 命令,将对象的所有权重新分配给其他角色。由于 REASSIGN OWNED 无法跨库执行,因此必须在每个数据库中运行它。如果是跨数据库共享对象,第一个 REASSIGN OWNED 命令执行时,就更改了它们的所有权,例如数据库或表空间。
使用 DROP OWNED 命令,删除剩余的对象。同样,此命令无法跨库执行,因此必须在每个数据库中运行它。此外,DROP OWNED 不会删除整个数据库或表空间,因此,如果角色拥有任何尚未转让给新所有者的数据库或表空间,则必须手动执行删除数据库或表空间。
DROP OWNED 还负责删除相应的权限。由于 REASSIGN OWNED 不涉及此类对象,因此通常需要同时运行 REASSIGN OWNED 和 DROP OWNED(按此顺序)以完全删除要删除的角色的依赖项。
简而言之,删除已用于拥有对象的角色的最通用方法是:
REASSIGN OWNED BY doomed_role TO successor_role;
DROP OWNED BY doomed_role;
-- 每个数据库中,重复上述命令
DROP ROLE doomed_role;
如果没有处理干净,就尝试 DROP ROLE,它将发出消息,指出哪些对象需要重新分配或删除。
(5)预定义角色
PostgreSQL 提供了一组预定义的角色。
角色 | 被允许的访问 |
---|---|
pg_read_all_data | 读取所有数据(表、视图、序列):具有 SELECT 权限,对所有 schema 具有 USAGE 权限;即使没有显式声明拥有这些权限。此角色没有设置角色属性 BYPASSRLS。如果正在使用 RLS,则管理员可能希望在此角色被授予的角色上设置 BYPASSRLS。 |
pg_write_all_data | 写入所有数据(表、视图、序列):具有 INSERT、UPDATE 和 DELETE 权限以及对所有 schema 具有 USAGE 权限;即使没有显式声明拥有这些权限。此角色没有设置角色属性 BYPASSRLS。如果正在使用 RLS,则管理员可能希望在此角色被授予的角色上设置 BYPASSRLS。 |
pg_read_all_settings | 读取所有配置变量,甚至包括通常仅对超级用户可见的变量。 |
pg_read_all_stats | 读取所有 pg_stat_* 视图并使用各种与统计相关的扩展,甚至是通常仅对超级用户可见的扩展。 |
pg_stat_scan_tables | 执行监控功能,这些功能可能会持续很长时间,并且可能对表执行 ACCESS SHARE 锁。 |
pg_monitor | 读取各种监控视图/执行各种监控功能。此角色是 pg_read_all_settings、pg_read_all_stats 和 pg_stat_scan_tables 的成员。 |
pg_database_owner | 没有。成员由当前数据库所有者组成。 |
pg_signal_backend | 向另一个后端发出信号以取消查询或终止其会话。 |
pg_read_server_files | 使用 COPY 或其他文件访问功能时,允许读取文件【即那些在服务器上数据库可以访问的文件】。 |
pg_write_server_files | 使用 COPY 或其他文件访问功能时,允许写入文件【即那些在服务器上数据库可以访问的文件】。 |
pg_execute_server_program | 使用 COPY 或调用函数(函数将执行服务端程序)时,允许在数据库服务器上执行程序【以运行数据库的用户 的身份来执行程序】。 |
pg_checkpoint | 允许执行 CHECKPOINT 命令。 |
pg_monitor、pg_read_all_settings、pg_read_all_stats 和 pg_stat_scan_tables 角色旨在允许管理员轻松配置角色以监视数据库服务器。它们授予一组通用权限,允许角色读取通常仅限于超级用户的各种有用的配置设置、统计信息和其他系统信息。
pg_database_owner 角色具有一个隐式的、依赖于情境的成员,即当前数据库的所有者。与任何角色一样,它可以拥有对象或接收访问权限的授予。因此,一旦 pg_database_owner 在模板数据库
中拥有权限,从该模板实例化的数据库
的所有者都将行使这些权限。pg_database_owner 不能是任何角色的成员,并且不能具有非隐式成员。最初,此角色拥有(模板数据库) public 模式(schema),因此每个(从该模板实例化的)数据库所有者都管理 public 模式的本地使用。
pg_signal_backend 角色旨在允许管理员启用受信任但非超级用户的角色,以向其他后端发送信号。目前,此角色允许发送信号以取消另一个后端上的查询或终止其会话。但是,被授予此角色的用户无法向超级用户拥有的后端发送信号。
pg_read_server_files、pg_write_server_files 和 pg_execute_server_program 角色旨在允许管理员拥有受信任但非超级用户的角色,这些角色能够以运行数据库的用户身份访问文件,并在数据库服务器上运行程序。由于这些角色能够访问服务器文件系统上的任何文件,因此它们在直接访问文件时会绕过所有数据库级权限检查,并且可用于获得超级用户级访问权限,因此在向用户授予这些角色时应非常小心。
预定义角色的使用例子:
GRANT pg_signal_backend TO admin_user;
(6)函数安全
-
PostgreSQL 仅允许超级用户创建以
不可信语言
编写的函数。
函数在后端服务器进程内运行,具有数据库服务器守护程序的操作系统权限。如果用于该函数的编程语言允许未经检查的内存访问,则可以更改服务器的内部数据结构。因此,此类函数可以绕过任何系统访问控制。允许进行此类访问的函数语言,被视为“不可信”语言。 -
严格控制谁可以定义对象。
函数、触发器和行级安全策略允许用户将代码插入到后端服务器中,其他用户可能会无意中执行这些代码。因此,最强大的保护措施是严格控制谁可以定义对象。 -
仅对
受信任所有者拥有的对象
进行查询。
从 search_path 中删除相关 schema——这些 schema 允许不受信任的用户创建对象。
3、grant 和 revoke 的使用
(1)grant
GRANT 命令有两个基本变体:一个用于角色的权限管理,另一个用于角色的成员管理。
角色的权限管理:
GRANT A ON B TO C [ WITH GRANT OPTION ] [ GRANTED BY role_specification ];
- 方括号 [] 代表可选内容;
- GRANTED BY:指定的授权者必须是当前用户。此子句当前以此形式存在,仅用于 SQL 兼容性;
即 role_specification 可以是: [ GROUP ] role_name | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER。 - WITH GRANT OPTION:权限的接收者可以将
授予给他的权限
授予其他角色。如果没有 WITH GRANT OPTION,则接收者无法将权限授予他人。 - A:一个或多个权限类型,B:权限类型的适用对象,C:一个或多个角色;
A 也可以是ALL [PRIVILEGES]
,不同的适用对象,ALL 代表的权限也不同,参考上面表格:《对象及其可以授予的权限》;
如果 A 是 TEMPORARY,可以简写为 TEMP;
当适用对象是表的时候,A 可以是表的一个或多个列名;
当适用对象是表的时候,B 可以是ALL TABLES IN SCHEMA schema_name [, ...]
;
当适用对象是 SEQUENCE 的时候,B 可以是ALL SEQUENCES IN SCHEMA schema_name [, ...]
;
当适用对象是 FUNCTION | PROCEDURE | ROUTINE 的时候,B 可以是ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA schema_name [, ...]
;
角色的成员管理:
GRANT D TO E [ WITH { ADMIN | INHERIT | SET } { OPTION | TRUE | FALSE } ] [ GRANTED BY role_specification ]
- D:一个或多个组角色;E:一个或多个成员角色;
- 更改现有成员,没有指定 ADMIN | INHERIT | SET 时,保留它们的原有值 ;
- 关键字 OPTION 被视为 TRUE 的同义词;
- ADMIN 选项:允许 成员角色 E 向其他人授予 组角色 D 的成员资格;若未指定,则此选项默认为 FALSE;
- INHERIT 选项:控制新成员资格的继承状态;如果设置为 TRUE,则会导致新成员从授予的角色继承。如果设置为 FALSE,则新成员不会继承。如果在创建新角色成员身份时未指定,则默认为新成员的 inheritance 属性。
- SET 选项:如果设置为 TRUE,则允许成员使用 SET ROLE 命令更改为授予的角色。如果一个角色是另一个角色的间接成员,则仅当存在一个授权链(每个授权链都具有 SET TRUE)时,它才能使用 SET ROLE 更改为该角色。此选项默认为 TRUE。
- GRANTED BY:指定由谁进行了授权操作,即指定授权人。授权人必须具有 ADMIN OPTION,除非是超级用户。如果授权人不是超级管理员,并且被撤销了 ADMIN OPTION,则也需要撤销相应的授权。
注意事项:
- 当
对象的非所有者
尝试对该对象执行 GRANT 权限时,如果对该对象没有任何权限,则该命令将彻底失败。只要某些权限可用,grant 命令就会继续,但它只会授予用户具有 grant option 的那些权限。如果用户不具有 grant option,将收到警告信息。 - Grant 和 revoke 命令能被对象的所有者执行。
组角色拥有的对象,其成员也可以对该对象执行 grant 和 revoke 命令,同时授权者将被记录为组角色。通过多个角色成员资格路径
间接持有所需的权限,则无法指定哪个包含 role 将被记录为已完成授权。在这种情况下,最佳做法是使用 SET ROLE 成为您想要执行 GRANT 的特定角色。
具有 grant option 的角色,也可以对该对象执行 grant 和 revoke 命令。
(2)revoke
角色的权限管理:
REVOKE [ GRANT OPTION FOR ] A ON B FROM C [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ];
- 如果指定了 GRANT OPTION FOR,则仅撤销权限的 grant 选项,而不撤销权限本身。否则,privilege 和 grant 选项都将被撤销。
- 如果存在对表的权限,同时也存在对列的权限,此时,如果撤销列的授权,不影响对表的所有列的访问;如果撤销对表的权限,将丧失对表的所有列的权限。
角色的成员管理:
REVOKE [ ADMIN OPTION FOR ] D ON B FROM E [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ];
- 如果指定了 ADMINOPTION FOR,则仅撤销权限的 admin 选项,而不撤销成员资格。否则,成员资格 和 admin 选项都将被撤销。
注意事项:
- 用户只能撤销该用户直接授予的权限。例如,如果用户 A 已将具有 grant 选项的权限授予用户 B,而用户 B 又将其授予用户 C,则用户 A 无法直接从 C 撤销该权限。相反,用户 A 可以撤销用户 B 的 grant 选项,并使用 CASCADE 选项,以便依次撤销用户 C 的权限。再举一个例子,如果 A 和 B 都向 C 授予了相同的权限,则 A 可以撤销自己的授权,但不能撤销 B 的授权,因此 C 实际上仍将拥有该权限。
(3)ALTER DEFAULT PRIVILEGES
用于定义默认访问权限,允许您设置将应用于将来创建的对象的权限。
ALTER DEFAULT PRIVILEGES [ FOR { ROLE | USER } target_role [, ...] ] [ IN SCHEMA schema_name [, ...] ] abbreviated_grant_or_revoke
-
它不会影响分配给现有对象的权限。
-
目前仅支持更改 schema、table(包括视图和外部表)、sequence、function 和 type(包括 domain)的默认权限。
- 对于此命令,function 包括 aggregates 和 procedures。因此,无法单独为函数和过程设置默认权限。
在此命令中,单词 FUNCTIONS 和 ROUTINES 是等效的(ROUTINES 是以后首选的函数和过程的标准术语)。
- 对于此命令,function 包括 aggregates 和 procedures。因此,无法单独为函数和过程设置默认权限。
-
默认权限可以全局设置(即针对当前数据库中创建的所有对象),也可以仅针对在指定 schema 中创建的对象来设置。
二者的关系如下:- schema 的默认权限是全局授予的:默认情况下(即没有执行过任何 ALTER DEFAULT PRIVILEGES 命令),或者之前执行过
未指定 schema 的 ALTER DEFAULT PRIVILEGES 命令
。 - 每个 schema 指定的默认权限将添加到特定对象类型的全局默认权限中。这意味着,无法通过Per-schema REVOKE 来撤销 schema 的全局默认权限。Per-schema REVOKE 仅用于撤回先前 Per-schema GRANT 的效果。
- schema 的默认权限是全局授予的:默认情况下(即没有执行过任何 ALTER DEFAULT PRIVILEGES 命令),或者之前执行过
-
只能更改
由您自己或您所在组的组角色
将来创建的对象的默认权限。
创建对象时,需要注意的是,任何对象类型的默认权限,通常向对象所有者
授予所有可授予的权限,并且也可能向 PUBLIC 授予一些权限。默认情况
4、权限管理的表格与视图
(1)查看用户
SELECT * FROM pg_user u ORDER BY u.usename;
(2)查看角色
SELECT * FROM pg_roles r ORDER BY r.rolname;
SELECT * FROM pg_roles WHERE rolname='postgres';
SELECT * FROM pg_authid;
(3)查看某用户的表权限
SELECT * FROM information_schema.table_privileges WHERE grantee = 'your_user_name';
(4)查看某用户在某表的列上的权限
SELECT * FROM information_schema.column_privileges WHERE grantee='your_user_name';
(5)查看某用户的 usage 权限
SELECT * FROM information_schema.usage_privileges WHERE grantee='your_user_name';
(6)查看某用户在存储过程函数的执行权限
SELECT * FROM information_schema.routine_privileges WHERE grantee='your_user_name';
(7)查看当前用户能够访问的数据类型
SELECT * FROM information_schema.data_type_privileges;
(8)查看用户自定义类型上授予的USAGE权限
SELECT * FROM information_schema.udt_privileges WHERE grantee='your_user_name';
(9)查看角色之间的成员关系
--角色之间的成员关系
SELECT
t2.rolname as "group_name",
t3.rolname as "member_name",
t4.rolname as "grantor_name",
t1.admin_option
FROM pg_auth_members t1
LEFT JOIN pg_authid t2 ON t2.oid = t1.roleid
LEFT JOIN pg_authid t3 ON t3.oid = t1.member
LEFT JOIN pg_authid t4 ON t4.oid = t1.grantor;
--查看特定角色的成员
SELECT
rolname as "member_name"
FROM pg_roles
WHERE oid IN
(
SELECT member
FROM pg_auth_members
WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'pg_read_all_settings')
);
(10)查看新建对象的默认权限
PostgreSQL 的全局默认权限并不直接通过一个单独的表或视图来展示,而是隐含在对象创建时的行为中。不过,你可以通过 pg_default_acl 表来查看和管理要为新创建对象分配的初始权限。这些权限可以被视为一种全局默认权限,因为它们适用于所有没有明确指定其他权限的新对象。对于特定 schema 的默认权限,你可以使用与上面类似的查询,但加上一个 WHERE 子句来限制结果只显示该 schema 的条目。
SELECT
pg_catalog.pg_get_userbyid(d.defaclrole) AS "Granter",
n.nspname AS "Schema",
CASE d.defaclobjtype
WHEN 'r' THEN 'table'
WHEN 'S' THEN 'sequence'
WHEN 'f' THEN 'function'
WHEN 'T' THEN 'type'
END AS "Type",
pg_catalog.array_to_string(d.defaclacl, E', ') AS "Access privileges"
FROM
pg_catalog.pg_default_acl d
LEFT JOIN
pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace
WHERE
n.nspname = 'abc' --指定 schema
ORDER BY
1, 2, 3;
5、案例:创建只读账号
在 PostgreSQL 中,创建一个只读权限的用户,通常意味着,你需要授予该用户对特定数据库中的表或视图有SELECT权限,但不授予其他如 INSERT、UPDATE、DELETE 等修改数据的权限。这可以通过 GRANT 语句来实现。但请注意,你可能还需要考虑对数据库和模式(schema)的权限,以及用户如何连接到数据库。
(1)登录
首先,你需要以超级用户或具有足够权限的用户身份登录到PostgreSQL数据库。
(2)创建用户
使用 CREATE ROLE 或 CREATE USER(CREATE USER 是 CREATE ROLE 的一个带有登录权限的别名)语句来创建新用户。
CREATE USER readonly_user WITH PASSWORD 'your_secure_password';
注意:从 PostgreSQL 10 开始,建议使用 CREATE ROLE 和 ALTER ROLE ... LOGIN 来创建用户,因为 CREATE USER 只是 CREATE ROLE 的一个快捷方式。
(3)设置访问数据库的权限
默认情况下,新创建的用户没有权限访问任何数据库。你需要允许用户连接到数据库。
GRANT CONNECT ON DATABASE your_database_name TO readonly_user;
(4)设置访问 schema 的权限
如果数据库中有多个模式,并且你只想让用户访问其中一个或几个模式,你可能还需要授予用户对这些 schema 的USAGE权限。
GRANT USAGE ON SCHEMA public TO readonly_user;
如果要对多个 schema 或所有 schema 授予权限,你可能需要为每个 schema 执行 GRANT 语句。可以动态生成这些语句:
SELECT 'GRANT USAGE ON SCHEMA ' || schemaname || ' TO readonly_user;' as "GrantStatement"
FROM
(
SELECT DISTINCT(table_schema) AS schemaname
FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
ORDER BY table_schema
) t;
(5)授予 SELECT 权限
最后,你需要为只读用户授予对特定表的 SELECT 权限。
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_user;
如果要对多个表或所有表授予权限,你可能需要为每个表执行 GRANT 语句。可以动态生成这些语句:
SELECT 'GRANT SELECT ON ' || table_schema || '.' || table_name || ' TO readonly_user;'
FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_type = 'BASE TABLE'
ORDER BY table_schema;
(6)设置新建对象的默认权限
注意:上面的命令仅对已经存在的表授予权限。对于将来创建的表,你需要使用 ALTER DEFAULT PRIVILEGES 来设置默认权限。
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_user;
这条命令会影响 public 模式中之后创建的所有表,自动授予 readonly_user 对这些新表的 SELECT 权限。
如果要对多个 schema 或所有 schema 设置新建对象的默认权限,你可能需要为每个 schema 执行 GRANT 语句。可以动态生成这些语句:
SELECT 'ALTER DEFAULT PRIVILEGES IN SCHEMA ' || schemaname || ' GRANT SELECT ON TABLES TO readonly_user;'
FROM
(
SELECT DISTINCT(table_schema) AS schemaname
FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
ORDER BY table_schema
) t;
(7)(可选)设置搜索路径:
如果你希望用户默认只访问特定的模式,可以设置其搜索路径。(6)函数安全
ALTER ROLE readonly_user SET search_path TO public;
完成以上步骤后,readonly_user 用户应该能够连接到数据库,并查询public模式(或你指定的其他模式)中的表,但不能修改这些表中的数据。
请根据你的具体需求调整这些步骤。