PostgreSQL 9.3.13,如何刷新不同用户的物化视图?

Ale*_*lex 12 postgresql permissions materialized-view errors postgresql-9.3

[我认为这个问题的根本原因是我不了解权限和特权......]

所以,为了设置舞台,我的设置是一个数据库,称之为MyDb

我有两个用户,spu1u1spu1是超级用户,u1是“普通”用户。MyDb的所有者是spu1。我想我还应该说u1具有从组角色继承的创建数据库和创建角色权限。

我有一个架构sch1,它是一个用户定义的架构。

在这个模式中,我有一个表,称为tbl1,还有一个物化视图,称为mvw1

TBL1的主人是SPU1,该mvw1的主人是U1


问题:

在当前设置中,如上所述,我无法将mvw1刷新为u1spu1。我只是得到以下有趣的错误(我已经广泛搜索了它,但没有找到任何可以完全解决我的设置的错误......)。

ERROR:  permission denied for relation tbl1
********** Error **********

ERROR: permission denied for relation tbl1
SQL state: 42501
Run Code Online (Sandbox Code Playgroud)

我发现

  1. 更改所有者mvw1SPU1,让我刷新为SPU1
  2. 运行下面的命令允许我将mvw1刷新为u1

我试图找出我需要授予普通用户u1缺少的权限(理想情况下所需的最低权限),以便我可以在以他们的身份登录时刷新此视图。

第一个选项虽然很高兴知道,但并不能解决我的问题。第二个选项似乎实际上是在向非超级用户授予超级用户权限,或者授予比我需要的更大的权限。

如果有人可以向我解释这里到底发生了什么(或指出我在解决问题所需的描述中遗漏了哪些信息),并让我知道我的第二个选择是否真的可行或更好的选择?

非常感谢!

Phi*_*lᵀᴹ 23

您可以使用在其所有者的安全上下文中运行的函数来执行此操作。

刷新视图的函数(使用拥有 MV/表的用户创建它):

CREATE OR REPLACE FUNCTION refresh_mvw1()
RETURNS void
SECURITY DEFINER
AS $$
BEGIN
REFRESH MATERIALIZED VIEW mvw1 with data;
RETURN;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

向您希望能够刷新视图的任何用户授予对该函数的执行权限:

-- Users have 'execute' permissions by default on functions!
revoke all on function refresh_mvw1() from public;
grant execute on function refresh_mvw1() to u1;
Run Code Online (Sandbox Code Playgroud)

刷新:

select refresh_mvw1();
Run Code Online (Sandbox Code Playgroud)

来自Postgres 文档

SECURITY DEFINER 指定函数将以创建它的用户的权限执行。

支持参数的版本:

CREATE OR REPLACE FUNCTION refresh_mv_xxx(table_name text)
RETURNS void
SECURITY DEFINER
AS $$
DECLARE sql text; 
BEGIN
sql := 'REFRESH MATERIALIZED VIEW ' || table_name || ' with data';
EXECUTE sql;
RETURN;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

...但我不确定动态 SQL 是否仍会作为定义者执行。

  • 首先将`table_name` 类型转换为`information_schema.sql_identifier` 不是更安全吗?只是为了避免任何滥用的可能性? (2认同)

ndr*_*uib 8

@Phil\xe1\xb5\x80\xe1\xb4\xb9\ 的第二个函数尝试容易受到 SQL 注入攻击,方法是使用:

\n
SELECT refresh_mv_xxx(\'example_mview_name with data; TRUNCATE TABLE example_table_name CASCADE; REFRESH MATERIALIZED VIEW example_mview_name\')\n
Run Code Online (Sandbox Code Playgroud)\n

其中example_mview_nameexample_table_name分别指您的任何物化视图和表。

\n

这在很多方面都是危险的。

\n

我建议要么使用他的第一个尝试,要么采用以下方式:

\n
CREATE OR REPLACE FUNCTION refresh_mv_dynamic(table_name text)\n    RETURNS void SECURITY DEFINER\nAS $$\nDECLARE\n    sql text;\nBEGIN\n    sql := format(\'REFRESH MATERIALIZED VIEW %I with data\', table_name);\n    EXECUTE sql;\n    RETURN;\nEND;\n$$\n    LANGUAGE plpgsql;\n
Run Code Online (Sandbox Code Playgroud)\n

format()带格式说明符%I

\n
\n

I将参数值视为 SQL 标识符,必要时用双引号引起来。值为空(相当于quote_ident)是错误的。

\n
\n


小智 5

另一种选择是创建 spu1 和 u1 所属/继承的(非超级用户)组角色(例如“刷新者”),并将该组角色指定为物化视图的所有者。