sql - 如何正确定义角色和权限(案例研究 - PostgreSQL)?

标签 sql database postgresql roles privileges

前段时间我来社区问我正在开发的系统的触发器的定义。我仍然发现自己在开发相同的系统,现在我对角色产生了怀疑。我是 PostgreSQL 的新手,即使按照文档进行操作,我也会遇到一些问题。

为了开发我的系统,我创建了 3 个用户:

  • dbadirector(译为dbadirector):相当于DBA,只有一个人使用。
  • dbagerente(翻译为 dbamanager):它是一个用户,无需更改表结构 操纵它的数据。同样的用户也可以创建 触发器、函数、索引等。
  • clisistema(翻译成clisystem):它是具有 连接到数据库。该用户可以执行 CRUD 操作, 但不能创建、删除、修改或移除中的现有对象 数据库。对于某些表,此用户的权限已被过滤。

创建用户、表、简单数据并设置权限后,pgAdmin 向我显示以下消息:

ERROR:  permission denied for relation tb_tabelas
CONTEXT:  SQL statement "SELECT 1 FROM ONLY "regrast"."tb_tabelas" x WHERE "tab_id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"

********** Error **********

ERROR: permission denied for relation tb_tabelas
SQL state: 42501
Context: SQL statement "SELECT 1 FROM ONLY "regrast"."tb_tabelas" x WHERE "tab_id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"

我正在使用 postgres 用户,但我不知道自己做错了什么。我不是在发表这些声明(至少不是直接发表):

"SELECT 1 FROM ONLY "regrast"."tb_tabelas" x WHERE "tab_id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"

这是我的用户的创建:

-- DROP OWNED BY dbadiretor CASCADE;    
DROP ROLE IF EXISTS dbadiretor; 
CREATE ROLE dbadiretor WITH     
    SUPERUSER                   
    CREATEDB                    
    CREATEROLE                  
    LOGIN                       
    REPLICATION             
    CONNECTION LIMIT 1  
    PASSWORD 'dbadiretor';  

-- DROP OWNED BY dbagerente CASCADE;    
DROP ROLE IF EXISTS dbagerente;     
CREATE ROLE dbagerente WITH     
    NOSUPERUSER                 
    NOCREATEDB                  
    NOCREATEROLE            
    NOINHERIT                   
    LOGIN                   
    NOREPLICATION       
    CONNECTION LIMIT 3  
    PASSWORD 'dbagerente';  

-- DROP OWNED BY clisistema CASCADE;
DROP ROLE IF EXISTS clisistema; 
CREATE ROLE clisistema WITH 
    NOSUPERUSER                 
    NOCREATEDB                  
    NOCREATEROLE                
    NOINHERIT                   
    LOGIN                       
    NOREPLICATION                   
    CONNECTION LIMIT 30             
    PASSWORD '12345';   

下面是权限分配:

-- #####################################
--  USUÁRIO: PUBLIC
-- #####################################

REVOKE ALL PRIVILEGES ON DATABASE "ELocadora" FROM PUBLIC;

-- #####################################
--  USUÁRIO: dbadiretor
-- #####################################

GRANT ALL PRIVILEGES ON SCHEMA regrast TO dbadiretor;
GRANT ALL PRIVILEGES ON DATABASE "ELocadora" TO dbadiretor;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA regrast TO dbadiretor;

-- #####################################
--  USUÁRIO: clisistema
-- #####################################

GRANT CONNECT ON DATABASE "ELocadora" TO clisistema;
GRANT USAGE ON SCHEMA regrast TO clisistema;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA regrast TO clisistema;

-- NÍVEL DE FILTRO 1

REVOKE TRUNCATE, REFERENCES, TRIGGER ON ALL TABLES IN SCHEMA regrast FROM clisistema;
REVOKE CREATE ON SCHEMA regrast FROM clisistema;
REVOKE TEMP ON DATABASE "ELocadora" FROM clisistema;

-- NÍVEL DE FILTRO 2

-- Tabela: TB_TABELAS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_tabelas FROM clisistema;

-- Tabela: TB_DADOS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_dados FROM clisistema;

-- Tabela: TB_MODIFICACOES
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_modificacoes FROM clisistema;

-- Tabela: TB_TIPOS_DE_LOGS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_tipos_de_logs FROM clisistema;

-- Tabela: TB_LOGS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_logs FROM clisistema;

-- Tabela: TB_HISTORICO_DE_PRODUTOS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_historico_de_produtos FROM clisistema;

-- Tabela: TB_CONFIGURACOES
-- Revogação: CD
REVOKE INSERT, DELETE ON TABLE regrast.tb_configuracoes FROM clisistema;

-- #####################################
--  USUÁRIO: dbagerente
-- #####################################

GRANT CONNECT ON DATABASE "ELocadora" TO dbagerente;
GRANT USAGE ON SCHEMA regrast TO dbagerente;
REVOKE INSERT, SELECT, UPDATE, DELETE ON ALL TABLES IN SCHEMA regrast FROM dbagerente;
GRANT CREATE ON SCHEMA regrast TO dbagerente;
GRANT REFERENCES, TRIGGER ON ALL TABLES IN SCHEMA regrast TO dbagerente;

我正在阅读 PostgreSQL documentation如果我想以任何方式修改它们,我需要为表设置一个合适的所有者。例如,关于 CREATE 特权:

CREATE

For schemas, allows new objects to be created within the schema. To rename an existing object, you must own the object and have this privilege for the containing schema.

因此,我所有的表的所有者都是 dbagerente 用户。作为 dbagerente,我可以修改结构。但作为 dbadiretor 或 postgres,我不能,这不是我想要的。对我来说,dbadiretor 和 postgres 是 super 用户,他们应该能够完成任何事情……或者不能? :/

再往前看......我必须注意*小心)其他数据库对象,例如函数、触发器等吗?

注意:我使用的是 PostgreSQL 9.5,数据库名为 ELocadora,模式名为 regrast。


对于这个提出的问题,如果可能的话(如果您不介意的话),对于像我这样的初学者,您是否有任何关于正确分配角色的建议?任何链接或提示都可以帮助我。

另外,只为实现日志而创建新用户有什么禁忌吗?系统事务(对于某些操作)可能最终不得不使用两种类型的用户来完成。

无论如何,感谢您的关注。

编辑

I'm suspecting that this error is showing up due to the dependencies between tables. In certain tables for certain foreign keys, I'm using ON DELETE and ON UPDATE statements.

When entering data a first time, the data is entered without problem. However, if I delete them to reinsert them, this error appears.

Is there something to do with this?

我错了,这个信息是没有根据的。请忽略它。对不起。

编辑2

我记录了所有的过程,包括所有的步骤和明显的问题。一切从零开始。请看一看(4 分钟):

Here

打开的 SQL 文件代表正在进行的不同操作。它们按不同的步骤组织。再一次,我做错了什么?

编辑 3

我在我的代码中发现了一个小错误。非破坏性的(最初)。在记录插入代码中,我更改了这个:

INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('ID' , 'USU_ID' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%'));

进入这个:

INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('ID' , 'USU_ID' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));

@Chris Travers

[...] and therefore the table owner must have write access to the cascading table before anyone can delete from them.

[...] So the issue here is that the table owner doesn't have access.

但我使用的是 super 帐户。我的意思是,我正在使用 super 用户。理论上,这里没有任何限制,因为我是 super 用户,不是吗?我作为 super 用户正在尝试插入和删除表记录。但是我收到了这个错误。

这是给我错误的以下代码:

INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('ID' , 'USU_ID' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Login' , 'USU_LOGIN' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Senha' , 'USU_SENHA' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Apelido' , 'USU_APELIDO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Nascimento' , 'USU_NASCIMENTO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Cadastro' , 'USU_CADASTRO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Gênero' , 'USU_GENERO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Privilégio' , 'USU_PRIVILEGIO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('CEP' , 'USU_CEP' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Número Residencial' , 'USU_NUMERO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Complemento' , 'USU_COMPLEMENTO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));

如果我对此发表评论,一切正常。

最佳答案

没错。关于更改表格的共享能力,您有几个选项。

  1. 您可以将 dba 用户设置为 super 用户(这会绕过该用户的权限检查)或

  2. 您可以创建另一个角色(使用 INHERIT NOLOGIN)将所有权分配给该角色,并将该角色授予需要修改结构的任何人。添加这些选项的原因是这不是登录角色,而是管理共享权限的角色。授予此角色的权限(以及所有权!)在授予此权限的所有角色之间共享。

对于select用户的permission denied,你使用的是dbagerente用户吗?如果是这样,那是预料之中的,因为您当时撤销了对此的许可。如果不是,您使用的是哪个用户名?

编辑。请注意,此类 RI 触发器作为表所有者运行,因此表所有者必须具有对级联表的写入权限,然后任何人才能从中删除。

您通过(在回滚的事务中)进行测试:

BEGIN;
ALTER TABLE ... DISABLE TRIGGER ALL;
-- statements that are failing here
ROLLBACK;

所以这里的问题是表所有者没有访问权限。根据我的经验,我必须添加授予表所有者的选择和删除权限(如果你也有更新,你可能需要更新)。\

EDIT2:如何重现

 CREATE USER myuser;

现在以我的用户身份登录:

 CREATE TABLE ctest1 (id int primary key);
 INSERT INTO ctest1 (id) SELECT generate_series(0, 10);
 CREATE TABLE ctest2 (id int references ctest1(id) on delete cascade);
 INSERT INTO ctest2 (id) SELECT generate_series(0, 10);
 REVOKE ALL ON ctest2 FROM myuser; -- nonsuperuser owner

现在以 postgres( super 用户)身份登录:

 DELETE FROM ctest1 WHERE id = 4;
 -- throws the error
 GRANT DELETE ON ctest2 TO myuser;
 DELETE FROM ctest1 WHERE id = 4;
 -- throws the error
 GRANT SELECT ON ctest2 TO myuser;
 DELETE FROM ctest1 WHERE id = 4; -- success

关于sql - 如何正确定义角色和权限(案例研究 - PostgreSQL)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37576679/

相关文章:

SQL 唯一的两列组合

python - SQL : Insert and Update a new column from existing column

mysql - 当日期字段包含特定小时/分钟时 SQL 更新日期字段

php - 如何将结果 SQL 不同查询设置为一个或不同的变量?

database - Postgres 数据库错误 : relation does not exist

postgresql - 将 CSV 导入 Postgres 并在需要时更新/替换任何字段

java - SQL 不应该在 java 中运行

sql-server - SQL Server 数据库恢复失败 - 版本冲突

java - 如果表存在则跳过 liquibase 更改

database - 最佳 Riak 存储策略