Skip to content

第 6 章 RLS 策略实战:亲手写"谁能看哪一行"

三次铺垫,今天兑现:第一册第 15 章立了规矩(没开 RLS 的表约等于公开),第三册第 8 章认了脸(create policy 是 SQL),这一章,亲手读写。

先懂为什么 RLS 非存在不可。传统架构里,前端永远隔着后端说话,权限由后端代码把守。而 Supabase 的架构允许前端带着用户的身份令牌直连数据库——快、省事,但把守者没了中间层可站,只能住进数据库本身。RLS(Row Level Security,行级安全)就是刻在每张表上的门规。

机制两句话说完:表一旦开启 RLS,默认拒绝一切;每条 policy 是一条"允许"——为某种操作、某种人,开一条缝。核心咒语只有一个:auth.uid()——"现在敲门的这个人的用户编号"。看第一块标本:

sql
alter table certificates enable row level security;

create policy "owner can read own certificates"
on certificates for select
using ( auth.uid() = owner_id );

逐行读:给这张表挂上门规;立一条名字讲人话的规矩;只管 select(读);条件——敲门人就是这一行的主人。using 读作"已存在的行,满足此条件才对你可见"。再看第二块标本,管"写入"的:

sql
create policy "user inserts own certificates"
on certificates for insert
with check ( auth.uid() = owner_id );

with check 读作"新来的行,必须满足此条件才收"——防止任何人替别人塞数据。这一对分清,RLS 就通了:using 管旧行给不给看、给不给改;with check 管新行收不收。顺带一种特殊写法:using (true) 是"谁都能看",用于确实要公开的数据(比如凭证的公开验证页)。写 true 没有错,但必须是故意的公开,不是忘了写条件。

然后是比写更重要的事:。policy 写完必须用两个身份测,而且要测满两面——自己看到自己的,且看不到别人的。只测前半句不算测:权限的 bug 全部藏在"看不到"那半句里。Supabase 面板可以模拟不同身份,或者干脆开两个测试账号。最后把这套变成制度:以后让 AI 建任何表,需求里永远带一句——"开启 RLS,写明每条 policy,并用人话向我解释每条的含义。"第一册那句追问,今天正式入宪。

出事时想起我

前端查询永远返回空数组,可表里明明有数据——RLS 默认拒绝、缺 policy,本层最经典症状;用户 A 看到了 B 的数据——policy 条件写松了,按事故处理,立刻收紧并排查影响面;insert 报 new row violates row-level security——with check 没过,检查新行的归属字段。

关键领悟

RLS 的世界里,默认是关死的门,policy 是开出的缝。using 管旧行,with check 管新行;每条缝都要用"看得到自己 + 看不到别人"两面测过才算存在。

试一试(安全档:⚠ 只在测试表上做)

和 AI 一起建一张练手表,亲手写上面那两条 policy,然后用两个账号完成两面测试。整套流程在测试表上走熟之前,不碰真表的 policy——这句话本身,就值得抄进红线卡。

由 Charles Tao 与 Claude 协作写成——这本身就是这套书讲的工作方式。 · 许可