看起来这并不是一个简单的方法。但是你可以使用带有 security definer
选项的函数来实现所需的行为:
create or replace function fn_create_role(p_name text, p_password text, p_databases text[]) returns void
language plpgsql
security definer
as $$
begin
execute format('create role %I with login password %L;', p_name, p_password);
execute format('grant connect on database %s to %I', array_to_string(p_databases, ','), p_name);
return;
end $$;
请使用超级用户创建此函数。
然后,您可以使用NOCREATEROLE
选项创建角色,但授予该角色对此函数的EXECUTE
特权,并使用它来创建其他角色。
注意:您需要从特定数据库中撤销public
角色的connect
选项,以默认禁止角色连接到它们,例如:
revoke connect on database db1, db2 from public;
测试它:
作为超级用户(在我的情况下是nd
,他还拥有相同名称的模式)
postgres=# create database db1; create database db2;
CREATE DATABASE
CREATE DATABASE
postgres=# revoke connect on database db1, db2 from public;
REVOKE
postgres=# create role foo with login password 'bar' nocreatedb nocreaterole;
CREATE ROLE
postgres=# set role foo;
SET
postgres=> create role win with login password 'amp' nocreatedb nocreaterole;
ERROR: permission denied to create role
postgres=> set role nd;
SET
postgres=# grant usage on schema nd to foo;
GRANT
postgres=# grant execute on function nd.fn_create_role(text, text, text[]) to foo;
GRANT
postgres=# set role foo;
SET
postgres=> select nd.fn_create_role('win', 'amp', '{db1}');
┌────────────────┐
│ fn_create_role │
╞════════════════╡
│ │
└────────────────┘
(1 row)
在终端中执行以下命令:
$ psql -h localhost -d db1 -U win
用户 win 的密码:
psql (9.6.3)
SSL 连接(协议:TLSv1.2,加密方式:ECDHE-RSA-AES256-GCM-SHA384,位数:256,压缩:关闭)
键入 "help" 获取帮助。
win@db1=> \q
$ psql -h localhost -d db2 -U win
用户 win 的密码:
psql: FATAL: 对数据库 "db2" 没有权限
DETAIL: 用户没有 CONNECT 权限。