NextJS中Supabase RLS策略失效问题求助
问题背景
使用包含user_profile、stripe_customer、subscription的关联数据模型,在Next.js的getServerSideProps中执行以下查询:
const { data, error } = await supabase.from('user_profile').select(` subscription ( status ) `) .eq('user_id', session.user.id);
现有RLS配置:
user_profile表:auth.uid() = user_idstripe_customer表:auth.uid() = user_idsubscription表:
(auth.uid() = ( SELECT stripe_customer.user_id FROM stripe_customer WHERE (stripe_customer.id = subscription.stripe_customer_id)))
执行查询无结果,关闭subscription表RLS后正常返回;尝试将subscription表RLS改为auth.uid() <> NULL::uuid或auth.uid() = NULL::uuid,同样无记录返回。
核心问题
1. 关联RLS的权限链断裂
从user_profile关联查询subscription时,subscription的RLS规则依赖stripe_customer表的子查询,但stripe_customer自身的RLS规则auth.uid() = user_id会限制该子查询的结果——子查询执行时,上下文是subscription行,无法自动继承当前用户的权限上下文,导致子查询无法匹配到stripe_customer记录,最终subscription的RLS判断为false,所有行被过滤。
2. NULL比较逻辑错误
SQL中NULL是特殊值,不能用=或<>进行比较,auth.uid() = NULL::uuid和auth.uid() <> NULL::uuid永远返回false,自然不会返回任何记录。正确的NULL判断应该用IS NULL或IS NOT NULL。
修复方案
修改subscription表的RLS策略
使用EXISTS子查询明确关联stripe_customer并验证用户权限,确保子查询能通过stripe_customer的RLS校验:
EXISTS ( SELECT 1 FROM stripe_customer sc WHERE sc.id = subscription.stripe_customer_id AND sc.user_id = auth.uid() )
该写法会先验证stripe_customer中存在匹配当前用户且与subscription关联的记录,同时满足stripe_customer的RLS规则。
验证用户上下文
在getServerSideProps中确认supabase客户端已正确初始化并携带用户session,可通过打印auth.uid()验证当前用户ID是否与session.user.id一致。
数据关联校验
检查stripe_customer表中是否存在与当前用户user_id匹配的记录,且该记录的id与subscription表的stripe_customer_id对应。
内容的提问来源于stack exchange,提问作者Sam

