我有一个 Postgres 数据库,其中有一个表
profile
。该表有两列:id
和 username
。我已启用 RLS 并应用了以下策略。
schemaname | tablename | policyname | permissive | roles | cmd | qual | with_check
------------+-----------+-----------------------------+------------+----------+--------+------------------------------------------------------------+------------
public | profile | select_user_or_group_policy | PERMISSIVE | {public} | SELECT | (current_setting('myapp.username'::text, true) = username) |
public | profile | unrestricted_insert | PERMISSIVE | {public} | INSERT | | true
public | profile | unrestricted_update | PERMISSIVE | {public} | UPDATE | true | true
public | profile | unrestricted_delete | PERMISSIVE | {public} | DELETE | true |
myapp.username
由外部应用程序设置,但出于测试目的,通过调用 设置
select set_config('myapp.username', 'user1', false);
.
从数据库中选择数据时,我发现它按预期工作,仅返回用户名与
myapp.username
配置匹配的行。更新时,我希望策略允许我更新我在更新开始时可以看到的任何记录。我希望能够将 username
更改为其他用户,但这样做时出现以下错误。我很困惑,因为更新策略设置为 USING (true) WITH CHECK (true)
。
更新前的表(表的 id 列有主键,其他列没有限制。
id | 用户名 |
---|---|
1 | 用户1 |
2 | 用户2 |
UPDATE profile SET username = 'user2' WHERE id = 1;
ERROR: new row violates row-level security policy for table "profile"
问题是
SELECT
策略也用于检查新行,因此您无法执行使行看起来消失的更新。
参见源码中的注释(
get_row_security_policies()
中的函数src/backend/rewrite/rowsecurity.c
):
/*
* Get and add ALL/SELECT policies, if SELECT rights are required for
* this relation (eg: when RETURNING is used). These are added as WCO
* policies rather than security quals to ensure that an error is
* raised if a policy is violated; otherwise, we might end up silently
* dropping rows to be added.
*/