我有两张桌子。一个外键引用另一个表中的串行字段。我已将INSERT权限授予除所有者以外的角色,但我仍然无法插入包含外键的表中,除非我在包含引用字段的表上授予表UPDATE权限的所有者。 我不太明白为什么所有者需要具有UPDATE权限才能使另一个不同的角色(具有INSERT权限)能够在这种情况下插入一行。
这有点令人困惑,所以我提供了一个很简单的问题示例。
createuser -U postgres testowner -DIRS --pwprompt
createdb -U postgres -O testowner testdb
createuser -U postgres testupdater -DIRS --pwprompt
psql -d testdb -U testowner
CREATE TABLE a ( id serial PRIMARY KEY );
CREATE TABLE b ( a_id integer REFERENCES a(id) );
GRANT SELECT,INSERT ON ALL TABLES IN SCHEMA public TO testupdater;
GRANT USAGE,UPDATE ON SEQUENCE a_id_seq TO testupdater;
REVOKE INSERT, UPDATE ON ALL TABLES IN SCHEMA public FROM testowner;
INSERT INTO a VALUES (DEFAULT); -- as expected: ERROR: permission denied for relation a
\q
psql -d testdb -U testupdater
INSERT INTO a VALUES (DEFAULT);
SELECT id FROM a LIMIT 1; -- selects the first id (1)
INSERT INTO b VALUES (1); -- unexpected error: see below
\q
ERROR: permission denied for relation a
CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."a" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR SHARE OF x"
但是,如果我向testowner提供UPDATE权限(GRANT UPDATE ON a TO testowner;
),则上述插入有效。为什么testowner在这种情况下需要UPDATE?
注意:GRANT UPDATE ON a TO testupdater;
无效;似乎我必须将更新授予testowner角色。
答案 0 :(得分:6)
我认为问题是该select语句中的“FOR SHARE OF” - 为了能够创建该行锁,您至少需要对该表进行某种写访问。
e.g。如果我创建一个表并且只授予自己SELECT访问权限:
postgres@testdb=# create table t(t1_id serial primary key, value text);
NOTICE: CREATE TABLE will create implicit sequence "t_t1_id_seq" for serial column "t.t1_id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t_pkey" for table "t"
CREATE TABLE
postgres@testdb=# insert into t(value) values('foo');
INSERT 0 1
postgres@testdb=# grant select on t to steve;
GRANT
现在虽然我可以从表中读取行,但我无法锁定它们:
steve@testdb@[local] => select * from t;
t1_id | value
-------+-------
1 | foo
(1 row)
steve@testdb@[local] => select * from t for share;
ERROR: permission denied for relation t
现在进行猜测...可能外键的实现通过检查外部表中存在的目标行来工作,并根据源表或目标表的所有者为其设置授权上下文。 TBH我从来没有撤销表拥有者的权限,所以我以前没遇到过这个。
我认为这是因为你不想让一个帐户只是因为他们创建了所有表而访问所有表?我建议:
set session authorization
,以无法登录访问权限的某个用户(例如数据库所有者)执行架构更改