PostgreSQL 用户和角色(二)

发布时间 2023-06-26 06:51:15作者: 晓枫的春天

对象授权

使用新创建的用户(wdh)连接数据库(test) 

[hui@hadoop201 ~]$ psql -h hadoop201 -p 5432 -U wdh test
Password for user wdh: 
psql (12.13)
Type "help" for help.

执行查询表提示

test=>  select * from employees;
ERROR:  permission denied for table employees

这里报错了:原因是 wdh 这个用户无权限对 相关表的查询权限。PostgreSQL使GRANT语句进行数据库对象的授权操作。以表为例,基本的授权语法如下:

GRANT privilege_list | ALLON [ TABLE ] table_nameTO role_name;

其中,privilege_list权限列表可以是SELECT、INSERT、UPDATE、DELETE、TRUNCATE等,ALL表示表上的所有权限。例如,使用postgres用户连接hrdb数据库后执行以下语句:

grant select, insert, update, delete on employees,jobs,departments to wdh;

该语句将employees、departments和jobs表上的增删改查权限授予了wdh用户。此时wdh用户就可以访问这些表中的数据:

SELECT first_name,last_name FROM employees;

 对表进行授权的GRANT语句还支持一些其他选项:

GRANT privilege_list | ALLON ALL TABLES IN SCHEMA schema_nameTO role_name;

ALL TABLES IN SCHEMA表示某个模式中的所有表,可以方便批量授权操作。例如:

GRANT SELECT  ON ALL TABLES IN SCHEMA public  to wdh

该语句将public模式中所有表的查询权限授予tony用户,也可以在GRANT 语句的最后指定一个WITH GRANT OPTION,意味着被授权的角色可以将该权限授权其他角色。例如

GRANT SELECT, INSERT, UPDATE, DELETE ON employees, departments, jobs TO wdh WITH GRANT OPTION;

此时,wdh用户不但拥有这些表上的访问权限,还可以将这些权限授予其他角色。除了授权表的访问权限之外,GRANT语句还支持字段、视图、序列、数据库、函数、过程、模式等对象的授权操作。授权操作的语句基本都类似,具体可以参考官方文档

撤销授权

与授权操作相反的就是撤销权限,PostgreSQL使REVOKE语句撤销数据库对象上的权限。同样以表为例,基本的撤销授权语句如下:
REVOKE privilege_list | ALLON TABLE table_nameFROM role_name;

其中的参数和GRANT语句一致。例如:

REVOKE SELECT, INSERT, UPDATE, DELETE    ON employees, departments, jobs   FROM wdh;

该语句撤销了用户wdh访问employees、departments以及jobs表的权限。REVOKE语句也支持对某个模式中的所有对象进行操作:

REVOKE privilege_list | ALLON ALL TABLES IN SCHEMA schema_nameFROM role_name;

例如以下语句撤销了用户tony在public模式中所有表上的查询权限:

REVOKE SELECT  ON ALL TABLES IN SCHEMA public FROM wdh;

与GRANT语句对应,REVOKE语句还支持字段、视图、序列、数据库、函数、过程、模式等对象的撤销授权操作。撤销授权的语句基本都类似,具体可以参考官方文档

角色成员

在现实的环境中,管理员通常需要管理大量的用户和对象权限。为了便于权限管理,减少复杂度,可以将用户进行分组,然后以组为单位进行权限的授予和撤销操作。为此,PostgreSQL引入了组(group)角色的概念。具体来说,就是创建一个代表组的角色,然后将该组的成员资格授予其他用户,让其成为该组的成员。首先,使用以下创建一个组角色:

CREATE ROLE group_name;

按照习惯,组角色通常不具有LOGIN特权,也就是不能作为一个用户登录。例如,我们可以先创建一个组managers:

CREATE ROLE managers;

然后,使用与对象授权操作相同的GRANT和REVOKE语句为组添加和删除成员:

GRANT group_name TO user_role, ... ;
REVOKE group_name FROM user_role, ... ;

将用户wdh添加为组managers的成员:

GRANT managers TO wdh;

最后一行输出显示了成员角色(wdh)所属的组(managers)。也可以将一个组添加为其他组的成员,因为组角色和非组角色并没有什么本质区别。

GRANT admin TO managers;

另外,PostgreSQL不允许设置循环的成员关系,也就是两个角色互相为对方的成员。

GRANT managers TO admin;

最后,不能将特殊角色PUBLIC设置为任何组的成员。组角色中的成员可以通过以下方式使用该组拥有的特权:

  • 首先,组中的成员可以通过SET ROLE命令将自己的角色临时性“变成”该组角色。此时,当前数据库会话拥有该组角色的权限,而不是登录用户的权限;并且会话创建的任何数据库对象归组角色所有,而不是登录用户所有。
  • 其次,对于具有INHERIT属性的角色,将会自动继承它所属的组的全部特权,包括这些组通过继承获得的特权。

考虑以下示例:

CREATE ROLE user1 LOGIN INHERIT;
CREATE ROLE net_admins NOINHERIT;
CREATE ROLE sys_admins NOINHERIT;
GRANT net_admins TO user1;
GRANT sys_admins TO net_admins;
使用角色user1登录之后,数据库会话将会拥有user1自身的特权和net_admins所有的特权,因为user1“继承”了net_admins的特权。但是,会话还不具有sys_admins所有的特权,因为即使user1间接地成为了sys_admins的成员,通过net_admins获得的成员资格具有NOINHERIT属性,也就不会自动继承权限。
如果执行了以下语句:
SET ROLE net_admins;

会话将会拥有net_admins所有的特权,但是不会拥有user1自身的特权,也不会继承sys_admins所有的特权。

如果执行了以下语句:

SET ROLE sys_admins;

会话将会拥有sys_admins所有的特权,但是不会拥有user1或者net_admins所有的特权。如果想要恢复初始状态的会话特权,可以执行以下任意语句:

SET ROLE user1;
SET ROLE NONE;
RESET ROLE;

在SQL标准中,用户和角色之间存在明确的差异,用户不会自动继承特权,而角色会继承特权。PostgreSQL可以实现这种行为,只需要为角色设置INHERIT属性,而为用户设置NOINHERIT属性。但是,为了兼容8.1之前的版本实现,PostgreSQL默认为所有的角色都设置了INHERIT属性,这样用户总是会继承它所在组的权限。只有数据库对象上的普通权限可以被继承,角色的LOGIN、SUPERUSER、CREATEDB以及CREATEROLE属性可以被认为是一些特殊的权限,不会被继承。如果想要使用这些权限,必须使用SET ROLE命令设置为具有这些属性的角色。基于上面的示例,我们可以为net_admins角色指定CREATEDB和CREATEROLE属性。

ALTER ROLE net_admins CREATEDB, CREATEROLE;

然后再使用user1连接数据库,会话不会自动具有这些特权,而是需要执行以下命令:

SET ROLE net_admins;

删除角色

删除角色的语句如下:

DROP ROLE name;

如果删除的是组角色,该组中的成员关系会自动从组中删除,但是这些成员角色自身不会受到任何影响。以下示例删除了角色admin:

drop role admin

由于角色可以拥有数据库中的对象,也可以拥有访问其他对象的权限,删除角色通常不仅仅只是一个简单的DROP ROLE语句。在删除角色之前,需要删除它所拥有的对象,或者将这些对象重新赋予其他的角色;同时还需要撤销授予该角色的权限。详细信息可以参考官方文档