关于sql:postgresql-查看架构特权

postgresql - view schema privileges

是否可以运行查询以显示特定模式上当前分配的特权?

即按以下方式分配的特权:

1
GRANT USAGE ON SCHEMA dbo TO MyUser

我试过了

1
2
SELECT *
FROM information_schema.usage_privileges;

但这只会将授予返回给内置PUBLIC角色。 相反,我想查看哪些用户已获得各种架构的特权。

注意:我实际上使用的是Amazon Redshift而不是纯PostgreSQL,但如果在Amazon Redshift中无法做到这一点,我将接受纯PostgreSQL答案。 (尽管我怀疑是这样)


在控制台util psql中:

1
\dn+

会告诉你

1
     Name      |  Owner   |   Access privileges   |      Description

列出当前用户的所有模式及其特权:

1
2
3
4
5
6
7
8
9
WITH"names"("name") AS (
  SELECT n.nspname AS"name"
    FROM pg_catalog.pg_namespace n
      WHERE n.nspname !~ '^pg_'
        AND n.nspname <> 'information_schema'
) SELECT"name",
  pg_catalog.has_schema_privilege(CURRENT_USER,"name", 'CREATE') AS"create",
  pg_catalog.has_schema_privilege(CURRENT_USER,"name", 'USAGE') AS"usage"
    FROM"names";

响应将例如:

1
2
3
4
5
6
  name   | CREATE | usage
---------+--------+-------
 public  | t      | t
 test    | t      | t
 awesome | f      | f
(3 ROWS)

在此示例中,当前用户不是awesome模式的所有者。

您可能会猜到,对特定架构的类似要求:

1
2
3
4
5
SELECT
  pg_catalog.has_schema_privilege(
    CURRENT_USER, 'awesome', 'CREATE') AS"create",
  pg_catalog.has_schema_privilege(
    CURRENT_USER, 'awesome', 'USAGE') AS"usage";

和回应:

1
2
3
 CREATE | usage
--------+-------
 f      | f

如您所知,对于当前模式可以使用pg_catalog.current_schema()

在所有可能的特权中

1
2
3
4
5
6
7
8
9
10
11
12
-- SELECT
-- INSERT
-- UPDATE
-- DELETE
-- TRUNCATE
-- REFERENCES
-- TRIGGER
-- CREATE
-- CONNECT
-- TEMP
-- EXECUTE
-- USAGE

模式仅允许使用CREATEUSAGE

current_schema()一样,current_user可以替换为特定角色。

current列的奖金

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
WITH"names"("name") AS (
  SELECT n.nspname AS"name"
    FROM pg_catalog.pg_namespace n
      WHERE n.nspname !~ '^pg_'
        AND n.nspname <> 'information_schema'
) SELECT"name",
  pg_catalog.has_schema_privilege(CURRENT_USER,"name", 'CREATE') AS"create",
  pg_catalog.has_schema_privilege(CURRENT_USER,"name", 'USAGE')  AS"usage",
 "name" = pg_catalog.current_schema() AS"current"
    FROM"names";

--   name   | create | usage | current
-- ---------+--------+-------+---------
--  public  | t      | t     | t
--  test    | t      | t     | f
--  awesome | f      | f     | f
-- (3 rows)

WITH |系统信息功能|授予(特权)


特权存储在pg_namespace的nspacl字段中。由于它是一个数组字段,因此您必须进行一些精美的编码才能对其进行解析。此查询将为您提供用于用户和组的Grant语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT
'grant ' || SUBSTRING(
          CASE WHEN charindex('U',split_part(split_part(array_to_string(nspacl, '|'),pu.usename,2 ) ,'/',1)) > 0 THEN ',usage ' ELSE '' END
          ||CASE WHEN charindex('C',split_part(split_part(array_to_string(nspacl, '|'),pu.usename,2 ) ,'/',1)) > 0 THEN ',create ' ELSE '' END
       , 2,10000)
|| ' on schema '||nspname||' to"'||pu.usename||'";'
FROM pg_namespace pn,pg_user pu
 WHERE  array_to_string(nspacl,',') LIKE '%'||pu.usename||'%' --and pu.usename='<username>'
AND nspowner > 1
UNION
SELECT
'grant ' || SUBSTRING(
          CASE WHEN charindex('U',split_part(split_part(array_to_string(nspacl, '|'),pg.groname,2 ) ,'/',1)) > 0 THEN ',usage ' ELSE '' END
          ||CASE WHEN charindex('C',split_part(split_part(array_to_string(nspacl, '|'),pg.groname,2 ) ,'/',1)) > 0 THEN ',create ' ELSE '' END
       , 2,10000)
|| ' on schema '||nspname||' to group"'||pg.groname||'";'
FROM pg_namespace pn,pg_group pg
 WHERE array_to_string(nspacl,',') LIKE '%'||pg.groname||'%' --and pg.groname='<username>'
 AND nspowner > 1


这就是psql在内部使用的内容:)

1
2
3
4
5
6
7
8
SELECT n.nspname AS"Name",
  pg_catalog.pg_get_userbyid(n.nspowner) AS"Owner",
  pg_catalog.array_to_string(n.nspacl, E'
'
) AS"Access privileges",
  pg_catalog.obj_description(n.oid, 'pg_namespace') AS"Description"
FROM pg_catalog.pg_namespace n
WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'
ORDER BY 1;

尝试以下一项(适用于PUBLIC角色):

1
2
3
4
5
6
7
8
9
10
SELECT nspname,
       COALESCE(NULLIF(ROLE.name,''), 'PUBLIC') AS name,
       SUBSTRING(
          CASE WHEN POSITION('U' IN split_part(split_part((','||array_to_string(nspacl,',')), ','||ROLE.name||'=',2 ) ,'/',1)) > 0 THEN ', USAGE' ELSE '' END
          || CASE WHEN POSITION('C' IN split_part(split_part((','||array_to_string(nspacl,',')), ','||ROLE.name||'=',2 ) ,'/',1)) > 0 THEN ', CREATE' ELSE '' END
       , 3,10000) AS privileges
FROM pg_namespace pn, (SELECT pg_roles.rolname AS name
   FROM pg_roles UNION ALL SELECT '' AS name) AS ROLE
 WHERE (','||array_to_string(nspacl,',')) LIKE '%,'||ROLE.name||'=%'
 AND nspowner > 1;

适用于AWS Redshift的组合版本(组,用户,PUBLIC):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    SELECT *
FROM (SELECT CASE
               WHEN charindex ('U',SPLIT_PART(SPLIT_PART(ARRAY_TO_STRING(nspacl,'|'),pu.usename,2),'/',1)) > 0 THEN ' USAGE'
               ELSE ''
             END ||CASE WHEN charindex('C',SPLIT_PART(SPLIT_PART(ARRAY_TO_STRING(nspacl,'|'),pu.usename,2),'/',1)) > 0 THEN ' CREATE' ELSE '' END AS rights,
             nspname AS schema,
             '' AS ROLE,
             pu.usename AS USER
      FROM pg_namespace pn,
           pg_user pu
      WHERE ARRAY_TO_STRING(nspacl,',') LIKE '%' ||pu.usename|| '%'
      --and pu.usename='<username>'
      AND   nspowner > 1

  UNION

      SELECT CASE
               WHEN charindex ('U',SPLIT_PART(SPLIT_PART(ARRAY_TO_STRING(nspacl,'|'),pg.groname,2),'/',1)) > 0 THEN ' USAGE '
               ELSE ''
             END ||CASE WHEN charindex('C',SPLIT_PART(SPLIT_PART(ARRAY_TO_STRING(nspacl,'|'),pg.groname,2),'/',1)) > 0 THEN ' CREATE' ELSE '' END AS rights,
             nspname AS schema,
             pg.groname AS ROLE,
             '' AS USER
      FROM pg_namespace pn,
           pg_group pg
      WHERE ARRAY_TO_STRING(nspacl,',') LIKE '%' ||pg.groname|| '%'
      --and pg.groname='<username>'
      AND   nspowner > 1

  UNION

      SELECT CASE
               WHEN POSITION('U' IN SPLIT_PART(SPLIT_PART((',' ||array_to_string (nspacl,',')),',' ||roles.name|| '=',2),'/',1)) > 0 THEN ' USAGE'
               ELSE ''
             END
      || CASE
               WHEN POSITION('C' IN SPLIT_PART(SPLIT_PART((',' ||array_to_string (nspacl,',')),',' ||roles.name|| '=',2),'/',1)) > 0 THEN ' CREATE'
               ELSE ''
             END AS rights,
             nspname AS schema,
             COALESCE(NULLIF(roles.name,''),'PUBLIC') AS ROLE,
             '' AS USER
      FROM pg_namespace pn,
           (SELECT pg_group.groname AS name
            FROM pg_group
            UNION ALL
            SELECT '' AS name) AS roles
      WHERE (',' ||array_to_string (nspacl,',')) LIKE '%,' ||roles.name|| '=%'
      AND   nspowner > 1) privs

ORDER BY schema,rights


对于当前问题,可以尝试以下方法:

1
2
3
4
5
6
7
8
9
10
SELECT r.rolname AS role_name,
       n.nspname AS schema_name,
       p.perm AS privilege
FROM pg_catalog.pg_namespace AS n
    CROSS JOIN pg_catalog.pg_roles AS r
    CROSS JOIN (VALUES ('USAGE'), ('CREATE')) AS p(perm)
WHERE has_schema_privilege(r.oid, n.oid, p.perm)
--      AND n.nspname <> 'information_schema'
--      AND n.nspname !~~ 'pg\_%'
--      AND NOT r.rolsuper

在我遇到过很多对象和用户的数据库上,性能可能会很低。所以我有使用aclexplode()默认功能的可能解决方法,如下所示:

1
2
3
4
5
6
7
8
9
SELECT  oid_to_rolname(a.grantee) AS role_name,
        n.nspname AS schema_name,
        a.privilege_type AS privilege_type
FROM pg_catalog.pg_namespace AS n,
        aclexplode(nspacl) a
WHERE n.nspacl IS NOT NULL
        AND oid_to_rolname(a.grantee) IS NOT NULL
--      AND n.nspname <> 'information_schema'
--      AND n.nspname !~~ 'pg\_%'

但是请注意,最后一个不包括用户从PUBLIC角色获得的特权。
其中oid_to_rolname()是简单的自定义函数SELECT rolname FROM pg_roles WHERE oid = $1

并且,像@Jaisus一样,我的任务要求拥有所有用户所拥有的所有特权。所以我对tableviewscolumnssequencesfunctionsdatabase甚至default特权具有类似于schema特权的查询。

此外,还有一个有用的扩展pg_permission,在该扩展中,我可以获取所提供查询的逻辑,并出于我的目的对其进行了升级。


我知道这篇文章很旧,但是我根据不同的答案又做了一个查询,以使查询简短易懂。

1
2
3
4
5
6
7
8
SELECT
    nspname AS schema_name
    , r.rolname AS role_name
    , pg_catalog.has_schema_privilege(r.rolname, nspname, 'CREATE') AS create_grant
    , pg_catalog.has_schema_privilege(r.rolname, nspname, 'USAGE') AS usage_grant
FROM pg_namespace pn,pg_catalog.pg_roles r
WHERE array_to_string(nspacl,',') LIKE '%'||r.rolname||'%'
    AND nspowner > 1

我一直在想,有一天我会查询仅在一个视图中拥有所有权利。 ;)