postgresql - 查看架构权限

Posted

技术标签:

【中文标题】postgresql - 查看架构权限【英文标题】:postgresql - view schema privileges 【发布时间】:2014-03-28 14:04:31 【问题描述】:

是否可以运行查询来显示特定架构上当前分配的权限?

即像这样分配的权限:

GRANT USAGE ON SCHEMA dbo TO MyUser

我试过了

SELECT *
FROM information_schema.usage_privileges;

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

注意:我实际上使用的是 Amazon Redshift 而不是纯 PostgreSQL,但如果这在 Amazon Redshift 中不可行,我会接受纯 PostgreSQL 答案。 (虽然我怀疑是)

【问题讨论】:

查看psql 在执行\dp viewname 查询时的作用,方法是运行带有-E 标志的psql。应该让你开始。我不使用 Redshift,所以不再追求。 【参考方案1】:

在控制台实用程序 psql 中:

\dn+

会告诉你

     Name      |  Owner   |   Access privileges   |      Description   

【讨论】:

这只显示了“模式列表”下的公共数据库 如何解释访问权限列?我看到了lemon_service=U/postgres,但是=U/postgres 是什么意思?【参考方案2】:

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

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";

响应将是例如:

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

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

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

SELECT
  pg_catalog.has_schema_privilege(
    current_user, 'awesome', 'CREATE') AS "create",
  pg_catalog.has_schema_privilege(
    current_user, 'awesome', 'USAGE') AS "usage";

和回应:

 create | usage 
--------+-------
 f      | f

如您所知,可以将pg_catalog.current_schema() 用于当前架构。

所有可能的特权

-- SELECT
-- INSERT
-- UPDATE
-- DELETE
-- TRUNCATE
-- REFERENCES
-- TRIGGER
-- CREATE
-- CONNECT
-- TEMP
-- EXECUTE
-- USAGE

只有 CREATEUSAGE 允许用于架构。

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


奖金current

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 | System Information Functions | GRANT (privileges)

【讨论】:

为我工作,但 RECURSIVE 关键字在那里做任何不平凡的事情吗? PostgreSQL 文档似乎暗示一个真正的“递归”查询应该有一个UNION @user1071847,当然。 RECURSIVE 在这里是不必要的。感谢您指出。【参考方案3】:

权限存储在 pg_namespace 的 nspacl 字段中。因为它是一个数组字段,你必须做一些花哨的编码来解析它。此查询将为您提供用于用户和组的授权语句:

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 

【讨论】:

也许我疯了,但我的 9.4 安装似乎没有 charindex。这是某种自定义功能吗? 不,它不是自定义函数。看起来您指的是 Postgres,而不是拥有它的 Redshift。在 Postgres 中,我认为它已被弃用,等效函数是 strpos。【参考方案4】:

这是 psql 内部使用的 :)

SELECT n.nspname AS "Name",
  pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner",
  pg_catalog.array_to_string(n.nspacl, E'\n') 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;

【讨论】:

【参考方案5】:

试试这个(适用于 PUBLIC 角色):

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;

【讨论】:

【参考方案6】:

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

    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

【讨论】:

您是否对 aws RDS postgres db 进行此查询?我从几天开始就在找那个。如果你有它,那将是很大的帮助。【参考方案7】:

对于当前的问题可以试试这个:

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() 默认函数这样的解决方法:

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,我可以在其中获取所提供查询的逻辑,并出于我的目的对其进行了升级。

【讨论】:

【参考方案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 

我一直在想,总有一天我会提出一个查询,要求只在一个视图中拥有所有权利……总有一天。 ;)

【讨论】:

我只是认为它比之前的答案更具可读性(更少的字符串操作)并且符合纯 PostgreSQL 代码。如果你把它放到一个视图中,它是直接“可查询的”。例如:SELECT * FROM new_view WHERE usage_grant = true; 其实我有更短的,我马上编辑我的代码。 谢谢,这比其他一些答案更有帮助而且更清楚。【参考方案9】:

更简洁地说,可以这样做:

  SELECT 
    n.nspname AS schema_name
   FROM pg_namespace n
  WHERE  has_schema_privilege('my_user',n.nspname, 'CREATE, USAGE');

【讨论】:

【参考方案10】:

去年没有关于这个问题的更新。但是,在我看来,这个问题还有一个答案。

SELECT grantor, grantee, table_schema, table_name, privilege_type
FROM information_schema.table_privileges
WHERE grantee = 'userName';

这样可以详细查看表的权限。

我看到这个答案适用于不属于假定用户的数据库。对于部分访问授权,您可以使用它来验证对架构表的访问。

【讨论】:

以上是关于postgresql - 查看架构权限的主要内容,如果未能解决你的问题,请参考以下文章

postgresql的安装与基础语法

怎么查看postgresql数据库用户系统权限对象权限

PostgreSQL继承postgres的权限[重复]

Postgresql 角色无法访问其创建的架构

postgresql用户管理

PostgreSQL数据库中跨库访问解决方案