Supabase中用户仅读写自有数据的配置及数据库函数权限疑问
1. 配置的Select策略是否限制登录用户仅查看自己的任务?
是的,你配置的这个select策略可以实现仅允许已认证(authenticated)用户读取自己的任务:
create policy "Anonymous and permanent users can read their own tasks only" on public.tasks for select to authenticated using ((select auth.uid()) = user_id);
需要注意的是,策略名称里提到了匿名用户,但to authenticated指定了仅对已登录用户生效,匿名用户(未登录)会被拒绝访问tasks表的select操作。如果需要允许匿名用户有特定权限,需要单独配置针对anon角色的策略。
2. 数据库函数是否需要传入user_id参数?
不需要传入user_id参数,直接使用第二个不带参数的函数即可:
create or replace function get_tasks_without_date() returns setof tasks language plpgsql as $$ begin return query select * from tasks where date is null; end; $$;
原因是:PostgreSQL函数默认使用SECURITY INVOKER(调用者权限),执行函数时会沿用调用者的权限上下文,包括已生效的行级策略。也就是说,当已登录用户调用这个函数时,tasks表的select策略会自动生效,过滤出user_id = auth.uid()的行,再加上函数里的date is null条件,最终返回的就是该用户的无日期任务。
如果手动传入user_id并在函数里加条件,虽然也能实现效果,但属于冗余操作,还可能增加权限漏洞的风险(比如传入不属于自己的user_id)。
3. 调用函数时用户ID如何传递给Supabase?
当你在Android应用中使用已登录的supabaseClient调用RPC函数时:
supabaseClient.postgrest.rpc( function = "get_tasks_without_date").decodeList<Task>()
客户端会自动在请求头中携带当前登录用户的JWT令牌,PostgREST服务会解析这个令牌,提取用户ID并设置auth.uid()函数的返回值。行级策略中的auth.uid()就是从这里获取当前用户的ID,从而自动完成数据过滤。
安全拉取及修改数据的建议
覆盖所有操作的行级策略:除了select,还要为update、delete操作配置对应的策略,确保用户只能修改/删除自己的任务。例如:
-- Update策略 create policy "Users can update their own tasks" on public.tasks for update to authenticated using (auth.uid() = user_id) with check (auth.uid() = user_id); -- Delete策略 create policy "Users can delete their own tasks" on public.tasks for delete to authenticated using (auth.uid() = user_id);with check用于验证更新后的数据仍符合权限条件,防止用户将任务的user_id改为他人ID。关闭表的默认公共权限:执行以下语句撤销public角色对tasks表的所有权限,确保只有通过行级策略授权的用户能访问数据:
revoke all on public.tasks from public;谨慎使用SECURITY DEFINER函数:如果你的函数需要使用更高权限,不得不设置
SECURITY DEFINER,一定要限制函数的执行权限,避免被滥用。同时要避免在这类函数中直接处理用户输入,防止注入攻击。验证客户端输入:在insert/update操作中,通过行级策略的
with check条件或数据库约束,确保用户无法插入不属于自己的user_id数据。例如在tasks表中设置user_id为不可空,并默认值为auth.uid()(仅对已认证用户生效):alter table public.tasks alter column user_id set default auth.uid();依赖Supabase Auth管理用户:不要自行实现登录逻辑,使用Supabase提供的Auth SDK管理用户会话,确保只有合法的已认证用户能访问需要权限的资源。
内容的提问来源于stack exchange,提问作者Joyce Opio

