提问人:Killerpixler 提问时间:10/24/2023 最后编辑:Killerpixler 更新时间:10/25/2023 访问量:90
Supabase PSQL 更新与插入的行级安全策略
Supabase PSQL row level security policy for update vs insert
问:
我有一个 and (cols = worspace_id, profile_id) 表,并且想要实现软删除,所以有一个布尔列。因此,对于删除,我只需执行更新调用以设置为 。workspaces
profiles_workspaces
workspaces
is_deleted
workspaces
is_deleted
true
该策略允许用户仅查看他们添加到的未删除工作区。SELECT
workspaces
USING (id IN (SELECT profiles_workspaces.workspace_id FROM profiles_workspaces) AND is_deleted is FALSE)
该政策仅适用于两者,因为现在我很高兴让某人更新,只要他们能看到它。UPDATE
true
USING
CHECK
当我在数据库中的工作区行上手动设置该布尔值时,一切都很好。客户端不再看到该工作区。但是,当我想“删除”工作区时,supabase 不会执行更新,说它违反了 RLS 策略。is_deleted
当我从策略中删除时,我可以毫无问题地进行更新。AND is_deleted is FALSE
SELECT
所以我的问题是:我如何允许人们更新字段,而不让他们看到工作区,其中为 true?我知道我可以过滤 supabase select 语句,但用户可以直接点击 API 并通过更改 API 有效负载来查看他们之前添加到的“已删除”工作区,因此不让这些行通过 RLS 查看似乎要简单得多。is_deleted
true
is_deleted
编辑:完整的政策声明:
工作区 - 选择
create policy "Enable SELECT for the workspace their user is added to"
on "public"."workspaces"
as permissive
for select
to authenticated
USING (id IN (SELECT profiles_workspaces.workspace_id FROM profiles_workspaces) AND is_deleted is FALSE)
工作区 - 更新
create policy "Enable UPDATE for the workspace their user is added to"
on "public"."workspaces"
as permissive
for update
to authenticated
using (true) with check (true);
profiles_workspaces - 选择
create policy "Enable SELECT for the workspace list their user is added to"
on "public"."profiles_workspaces"
as permissive
for select
to authenticated
using (
(profile_id = (auth.jwt()->>'sub')::uuid)
);
表架构
工作区
- ID uuid
- 名称 varchar(255)
- 蛞蝓瓦查尔(255)
- is_deleted boolean default false
profiles_workspaces
- profile_id uuid
- workspace_id uuid
并且与 supabase 的相同,以防有人想知道 的选择策略。profiles.id
auth.users.id
profiles_workspaces
编辑 2 解决方法
看起来这是一个PSQL错误(谢谢LaurenzAlbe!因此,这里有一个解决方法可以解决问题。不是超级干净,但它有效。
- 我将布尔列添加到
is_visible
workspaces
- 在 SELECT 策略中替换为
is_deleted IS FALSE
is_visible IS TRUE
- 添加此函数
CREATE OR REPLACE FUNCTION public.handle_workspace_deletion()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER set search_path = public
AS $function$
begin
IF new.is_deleted is true and old.is_visible is true then
update public.workspaces set is_visible = false where id = new.id;
end if;
return new;
end;
$function$
;
- 添加触发器
create trigger on_workspace_deleted
after update on public.workspaces
for each row execute procedure public.handle_workspace_deletion();
请注意,它必须是 AFTER 更新而不是 BEFORE。当我尝试在 BEFORE UPDATE 上运行该函数时(使用 ),当我尝试在工作区上更新时,我会遇到相同的 RLS 策略错误。但是,该功能有效!THEN
new.is_visible = false;
is_deleted
AFTER UPDATE
答:
我自己很惊讶应该使用策略来检查新行并导致错误,所以我问了邮件列表。这种行为似乎是故意的,给出的理由是FOR SELECT
如果可以执行 ,那将是令人惊讶的,但更新的行版本似乎消失了,因此行级别安全性应该可以防止这种情况发生
UPDATE
如果可以更新一行,使你无法再看到新版本,则可能会触发与你看不到的行的约束冲突,从而允许你获得有关这些不可见行的信息
您将不得不使用解决方法。
评论