GRANT — 定义访问特权
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } [, ...] | ALL [ PRIVILEGES ] } ON { [ TABLE ]table_name
[, ...] | ALL TABLES IN SCHEMAschema_name
[, ...] } TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { { SELECT | INSERT | UPDATE | REFERENCES } (column_name
[, ...] ) [, ...] | ALL [ PRIVILEGES ] (column_name
[, ...] ) } ON [ TABLE ]table_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { { USAGE | SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } ON { SEQUENCEsequence_name
[, ...] | ALL SEQUENCES IN SCHEMAschema_name
[, ...] } TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] } ON DATABASEdatabase_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON DOMAINdomain_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN DATA WRAPPERfdw_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON FOREIGN SERVERserver_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { EXECUTE | ALL [ PRIVILEGES ] } ON { FUNCTIONfunction_name
[ ( [ [argmode
] [arg_name
]arg_type
[, ...] ] ) ] [, ...] | ALL FUNCTIONS IN SCHEMAschema_name
[, ...] } TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON LANGUAGElang_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } ON LARGE OBJECTloid
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] } ON SCHEMAschema_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { CREATE | ALL [ PRIVILEGES ] } ON TABLESPACEtablespace_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] GRANT { USAGE | ALL [ PRIVILEGES ] } ON TYPEtype_name
[, ...] TOrole_specification
[, ...] [ WITH GRANT OPTION ] whererole_specification
can be: [ GROUP ]role_name
| PUBLIC | CURRENT_USER | SESSION_USER GRANTrole_name
[, ...] TOrole_name
[, ...] [ WITH ADMIN OPTION ]
GRANT
命令由两种基本的变体:一种授予在一个数据库对象(表、列、视图、外部表、序列、数据库、外部数据包装器、外部服务器、函数、过程语言、模式或表空间)上的特权,另一个授予一个角色中的成员关系。这些变体在很多方面都相似,但是也有很多不同,所以还是得分别描述它们。
这种GRANT
命令的变体将一个数据库对象上的指定特权交给一个或多个角色。如果有一些已经被授予,这些特权会被加入到它们之中。
还有一个选项可以授予一个或多个模式中同种类型的所有对象上的特权。这种功能当前只对表、序列和函数支持(但是注意ALL TABLES
会被认为是包括视图和外部表)。
关键词PUBLIC
指示特权要被授予给所有角色,包括那些可能稍后会被创建的角色。PUBLIC
可以被认为是一个被隐式定义的总是包含所有角色的组。任何特定角色都将具有直接授予给它的特权、授予给它作为成员所在的任何角色的特权以及被授予给PUBLIC
的特权。
如果指定了WITH GRANT OPTION
,特权的接收者可以接着把它授予给其他人。如果没有授权选项,接收者就不能这样做。授权选项不能被授予给PUBLIC
。
没有必要把权限授予给一个对象的拥有者(通常就是创建该对象的用户), 因为拥有者默认具有所有的特权(不过拥有者可能为了安全选择撤回一些 它们自己的特权)。
删除一个对象或者以任何方式修改其定义的权力是不被当作一个可授予特权的,它被固化在拥有者中,并且不能被授予和撤回(不过,相似地效果可以通过授予或者撤回在拥有该对象的角色中的成员关系来实现,见下文)。拥有者也隐式地拥有该对象的所有授权选项。
PostgreSQL 会把某些类型的对象上的默认特权授予给PUBLIC
。
默认在表、表列、序列、外部数据封装器、外部服务器、大对象、
模式或表空间上不会有特权会被授予给PUBLIC
。对于其他对象的类型,
被授予给PUBLIC
的默认特权是下面这些:数据库上的
CONNECT
以及TEMPORARY
(创建临时表)权限;
函数上的EXECUTE
特权;语言和数据类型(包括域)的USAGE
特权。当然,对象拥有者可以REVOKE
默认和专门授予的特权(为了最好的安全性,应该在创建该对象的同一个事务中发出REVOKE
,这样其他用户就没有时间窗口使用该对象)。还有,这些初始的默认特权设置可以使用ALTER DEFAULT PRIVILEGES命令修改。
可能的特权是:
SELECT
允许从指定表、视图或序列的任何列或者列出的特定列进行SELECT。还允许使用COPY TO。在UPDATE或DELETE中引用已有列值时也需要这个特权。对于序列,这个特权也允许使用currval
函数。对于大对象,这个特权允许读取对象。
INSERT
允许INSERT一个新行到指定表中。如果列出了特定的列,只有这些列能在INSERT
命令中被赋值(其他列将因此收到默认值)。还允许COPY FROM。
UPDATE
允许对指定表、视图或序列的任何列或者列出的特定列进行UPDATE(实际上,任何非平凡的UPDATE
命令也会要求SELECT
特权,因为它必须引用表列来判断哪些行要被更新或者为列计算新值)。除SELECT
特权之外,SELECT ... FOR UPDATE
以及SELECT ... FOR SHARE
也要求至少一列上的这个特权。对于序列,这个特权允许使用nextval
和setval
函数。对于大对象,这个特权允许写入或者截断对象。
DELETE
允许从指定的表中DELETE一行(实际上,任何非平凡的DELETE
命令也将要求SELECT
特权,因为它必须引用表列来判断要删除哪些行)。
TRUNCATE
允许在指定的表上TRUNCATE。
REFERENCES
允许创建引用指定表或指定表列的外键约束。(请参阅CREATE TABLE语句。)
TRIGGER
允许在指定的表上创建触发器(见CREATE TRIGGER语句)。
CREATE
对于数据库,允许在其中创建新模式或发布。
对于模式,允许在其中创建新的对象。要重命名一个已有对象,你必须拥有该对象并且具有所在模式的这个特权。
对于表空间,允许在其中创建表、索引和临时文件,并且允许创建使用该表空间作为默认表空间的数据库(注意撤回这个特权将不会更改现有对象的放置位置)。
CONNECT
允许用户连接到指定数据库。在连接开始时会检查这个特权(除了检查由pg_hba.conf
施加的任何限制之外)。
TEMPORARY
TEMP
允许在使用指定数据库时创建临时表。
EXECUTE
允许使用指定的函数以及使用在该函数之上实现的任何操作符。这是适用于函数的唯一一种特权类型(这种语法也可用于聚集函数)。
USAGE
对于过程语言,允许使用指定的语言创建函数。这是适用于过程语言的唯一一种特权类型。
对于模式,允许访问包含在指定模式中的对象(假定这些对象的拥有特权要求也满足)。本质上这允许被授权者在模式中“查阅”对象。如果没有这个权限,还是有可能看到对象名称,例如通过查询系统表。还有,在撤回这个权限之后,现有后端可能有语句之前已经执行过这种查阅,因此这不是一种阻止对象访问的完全安全的方法。
对于序列,这种特权允许使用currval
和nextval
函数。
对于类型和域,这种特权允许用该类型或域来创建表、函数和其他模式对象(注意这不能控制类型的一般“用法”,例如出现在查询中的该类型的值。它只阻止基于该类型创建对象。该特权的主要目的是控制哪些用户在一个类型上创建了依赖,这能够阻止拥有者以后更改该类型)。
对于外部数据包装器,这个特权允许使用该外部数据包装器创建新服务器。
对于服务器,这个特权允许使用该服务器创建外部表, 被授权者还可以创建、修改或删除与该服务器相关的他们自己的用户映射。
ALL PRIVILEGES
一次授予所有的可用特权。在PostgreSQL中,PRIVILEGES
关键词是可选的,但是在严格的 SQL 中是要求它的。
其他命令所要求的特权会被列在相应命令的参考页中。
GRANT
命令的这种变体把一个角色中的成员关系授予一个或者多个其他角色。一个角色中的成员关系是有意义的,因为它会把授予给一个角色的特权带给该角色的每一个成员。
如果指定了WITH ADMIN OPTION
,成员接着可以把该角色中的成员关系授予给其他用户,也可以撤回该角色中的成员关系。如果没有管理选项,普通用户就不能做这些工作。一个角色不被认为持有自身的WITH ADMIN OPTION
,但是它可以从一个会话用户匹配该角色的数据库会话中授予或撤回自身中的成员关系。数据库超级用户能够授予或撤回任何角色中任何人的成员关系。具有CREATEROLE
特权的角色能够授予或者撤回任何非超级用户角色中的成员关系。
和特权的情况不同,一个角色中的成员关系不能被授予PUBLIC
。还要注意这种形式的命令不允许噪声词GROUP
。
REVOKE命令被用来撤回访问特权。
从PostgreSQL 8.1 开始,用户和组的概念已经被统一到一种单一类型的实体(被称为一个角色)。因此不再需要使用关键词GROUP
来标识一个被授权者是一个用户或者一个组。在该命令中仍然允许GROUP
,但是它只是一个噪音词而已。
如果一个用户持有特定列或者其所在的整个表的特权,
该用户可以在该列上执行SELECT
、
INSERT
等命令。在表层面上授予特权
然后对一列撤回该特权将不会按照你希望的运作:
表级别的授权不会受到列级别操作的影响。
当一个对象的非拥有者尝试GRANT
该对象上的特权,如果该用户在该对象上什么特权都不拥有,该命令将立刻失败。只要有一些特权可用,该命令将继续,但是它将只授予那些用户具有授权选项的特权。如果不持有授权选项,GRANT ALL PRIVILEGES
形式将发出一个警告消息。而如果不持有命令中特别提到的任何特权的授权选项,其他形式将会发出一个警告(原则上这些语句也适用于对象拥有者,但是由于拥有者总是被视为持有所有授权选项,因此这种情况不会发生)。
需要注意的是,数据库超级用户可以访问所有对象而不管对象特权的设置。这可与 Unix 系统中的root
权力相提并论。对于root
来说,除非绝对必要,使用一个超级用户来操作是不明智的。
如果一个超级用户选择发出一个GRANT
或者REVOKE
命令,该命令将被执行,好像它是由被影响对象的拥有者发出的一样。特别地,通过这样一个命令授予的特权将好像是由对象拥有者授予的一样(对于角色成员关系,该成员关系好像是由该角色本身授予的一样)。
GRANT
以及REVOKE
也可以由一个不是受影响对象拥有者的角色完成,不过该角色是拥有该对象的角色的一个成员,或者是在该对象上持有特权的WITH GRANT OPTION
的角色的一个成员。在这种情况下,特权将被记录为由实际拥有该对象的角色授予或者是由持有特权的WITH GRANT OPTION
的角色授予。例如,如果表t1
被角色g1
拥有,u1
是它的一个成员,那么u1
可以把t1
上的特权授予给u2
,但是那些特权将好像是直接由g1
授予的。角色g1
的任何其他成员可以稍后撤回它们。
如果执行GRANT
的角色间接地通过多于一条角色成员关系路径持有所需的特权,将不会指定哪一个包含它的角色将被记录为完成了该授权。在这样的情况中,最好使用SET ROLE
来成为你想用其做GRANT
的特定角色。
授予一个表上的权限不会自动地扩展权限给该表使用的任何序列,包括绑定在SERIAL
列上的序列。序列上的权限必须被独立设置。
使用psql的\dp
命令可获得表和列上现有的特权的信息。例如:
=> \dp mytable Access privileges Schema | Name | Type | Access privileges | Column access privileges --------+---------+-------+-----------------------+-------------------------- public | mytable | table | miriam=arwdDxt/miriam | col1: : =r/miriam : miriam_rw=rw/miriam : admin=arw/miriam (1 row)
\dp
显示的项解释如下:
角色名=xxxx -- 被授予给一个角色的特权 =xxxx -- 被授予给 PUBLIC 的特权 r -- SELECT ("读") w -- UPDATE ("写") a -- INSERT ("追加") d -- DELETE D -- TRUNCATE x -- REFERENCES t -- TRIGGER X -- EXECUTE U -- USAGE C -- CREATE c -- CONNECT T -- TEMPORARY arwdDxt -- ALL PRIVILEGES (对于表,对其他对象会变化) * -- 用于前述特权的授权选项 /yyyy -- 授予该特权的角色
用户miriam
在创建了表mytable
并且执行了下面的操作后会看到上述例子的显示:
GRANT SELECT ON mytable TO PUBLIC; GRANT SELECT, UPDATE, INSERT ON mytable TO admin; GRANT SELECT (col1), UPDATE (col1) ON mytable TO miriam_rw;
对于非表对象,有其他的\d
命令可显示它们的特权。
如果一个给定对象的“Access privileges”列为空,表示该对象具有默认的特权(也就是,它的特权列为空)。默认特权总是包括拥有者的所有特权,并且如前所述根据对象类型可以包括一些PUBLIC
的特权。一个对象上的第一个GRANT
或者REVOKE
将实例化默认特权(例如,产生{miriam=arwdDxt/miriam}
)并且接着为每一个指定请求修改它们。类似地,显示在“Column access privileges”列中的项只用于带有非默认特权的列(注意,为了这个目的“default privileges”总是表示该对象类型的内建默认特权)。一个特权已经被一个ALTER DEFAULT PRIVILEGES
命令影响的对象将与一个显式特权项一起显示,该项包括ALTER
的效果)。
注意拥有者的隐式授权选项没有在访问特权显示中被标出。当授权选项被显式地授予给某人时,只会出现一个*
。
把表films
上的插入特权授予给所有用户:
GRANT INSERT ON films TO PUBLIC;
把视图kinds
上的所有可用特权授予给用户manuel
:
GRANT ALL PRIVILEGES ON kinds TO manuel;
注意虽然上述语句被一个超级用户或者kinds
的拥有者执行时确实会授予所有特权,但是当由其他人执行时将只会授予那些执行者拥有授权选项的权限。
把角色admins
中的成员关系授予给用户joe
:
GRANT admins TO joe;
根据 SQL 标准,ALL PRIVILEGES
中的PRIVILEGES
关键词是必须的。SQL 标准不支持在每个命令中设置超过一个对象上的特权。
PostgreSQL允许一个对象拥有者
撤回它们拥有的普通特权:例如,一个表拥有者可以通过撤回其自身拥有
的INSERT
、UPDATE
、DELETE
和TRUNCATE
特权让该表对它们自己只读。根据 SQL 标准
这是不可能发生的。原因在于PostgreSQL
认为拥有者的特权是由拥有者授予给它们自己的,因此它们也能够撤回它们。
在 SQL 标准中,拥有者的特权是有一个假设的实体“_SYSTEM”所授予。
由于不是“_SYSTEM”,拥有者就不能撤回这些权力。
根据 SQL 标准,授权选项可以被授予给PUBLIC
, PostgreSQL 只支持把授权选项授予给角色。
SQL 标准提供了其他对象类型上的USAGE
特权:字符集、排序规则、翻译。
在 SQL 标准中,序列只有一个USAGE
特权,它控制NEXT VALUE FOR
表达式的使用,该表达式等效于 PostgreSQL 中的函数nextval
。序列的特权SELECT
和UPDATE
是 PostgreSQL 扩展。应用序列的USAGE
特权到currval
函数也是一个 PostgreSQL 扩展(该函数本身也是)。
数据库、表空间、模式和语言上的特权都是PostgreSQL扩展。