You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Supabase JS API插入操作因行级安全(RLS)失败,但PostgreSQL控制台执行相同插入成功的问题排查

问题分析与解决方案

首先,我一眼就看到了最可能的问题:你在测试代码中使用了anonClient执行插入操作,但这个客户端是未认证的匿名实例,完全不符合你的RLS策略要求的authenticated角色

为什么会出现这种差异?

  • 在PostgreSQL控制台中,你手动执行了SET ROLE authenticated;,相当于模拟了已认证用户的身份,所以策略会按预期生效(第一次插入成功,第二次失败符合逻辑)。
  • 但在JS API代码里,你虽然调用了logInAs(newUser)登录用户,却用了anonClient来执行插入——这个客户端实例并没有携带认证后的JWT,PostgreSQL会把它识别为anon角色(匿名用户)。你的策略是明确限定给authenticated角色的,哪怕你把策略的WITH CHECK改成true,角色不匹配的话依然会触发RLS拒绝。

修复步骤

你需要使用登录后的已认证客户端实例来执行插入操作,而不是匿名客户端。具体修改方式取决于你的logInAs函数实现:

  1. 如果logInAs返回已认证的客户端:
// Given
const newUser = await createUser({ email: 'new_client+test@example.com' });
// 获取登录后的已认证客户端
const authenticatedClient = await logInAs(newUser);
// When - 用这个已认证客户端执行插入
const { data, error } = await authenticatedClient
  .from('clients')
  .insert([generateClient({}).record]);
  1. 如果logInAs是修改全局客户端的状态:
    确保你插入时使用的是那个被修改的全局客户端,而不是独立的anonClient。比如:
// 假设你有一个全局的supabase客户端实例
import supabase from '../supabase';

// Given
const newUser = await createUser({ email: 'new_client+test@example.com' });
await logInAs(newUser); // 这个函数会给supabase实例设置认证状态
// When - 用全局的已认证客户端执行插入
const { data, error } = await supabase
  .from('clients')
  .insert([generateClient({}).record]);

额外验证

你可以在插入前打印客户端的认证状态,确认是否携带了正确的JWT:

const { data: { session } } = await authenticatedClient.auth.getSession();
console.log(session?.user.id); // 应该输出newUser的ID,说明认证有效

内容的提问来源于stack exchange,提问作者Vlad Miller

火山引擎 最新活动