You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Supabase Flutter匿名UPSERT触发RLS权限错误的解决问询

Supabase UPSERT 触发RLS权限错误问题排查与解决

问题背景

我有一个名为users的Supabase表,包含唯一键文本列id_rc1、文本列version,其余字段均为可空状态。该表已启用行级安全(RLS),配置了匿名用户的INSERT和UPDATE策略(无法复制策略文本,以图片展示)。

使用supabase_flutter的INSERT命令可正常执行,但UPSERT命令始终失败:无论目标id_rc1对应的行是否存在,都会触发错误:"new row violates row-level security policy for table "users", code: 42501, details: Unauthorized, hint: null"。

测试代码

import 'package:flutter/foundation.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

late SupabaseClient supabase;
bool supabaseInitialized = false;
String supabaseProjectApiUrl = "https://REDACTED.supabase.co";
String supabasePublicAnonKey = "REDACTED";

void main() async {
  await initSupabase();
  supabaseUpsertTest();
}

Future<void> initSupabase() async {
  debugPrint("initSupabase START");
  try {
    await Supabase.initialize(url: supabaseProjectApiUrl, anonKey: supabasePublicAnonKey);
    supabase = Supabase.instance.client;
    debugPrint("initSupabase DONE");
    supabaseInitialized = true;
  } catch (err) {
    debugPrint("initSupabase ERROR: $err");
  }
}

Future<void> supabaseUpsertTest() async {
  if (supabaseInitialized) {
    final data = {"id_rc1": "ABC123", "version": "1.0"};
    try {
      debugPrint("Upsert START");
      final response = await supabase.from("users").upsert(data, onConflict: "id_rc1");
      // final response = await supabase.from("users").insert(data);
      if (response.error != null) throw response.error;
      debugPrint("Upsert SUCCESS");
    } catch (err) {
      debugPrint("Upsert ERROR: $err");
    }
  } else {
    debugPrint("Supabase not initialized");
  }
}

控制台错误输出

I/flutter (24043): initSupabase START
I/flutter (24043): supabase.supabase_flutter: INFO: ***** Supabase init completed *****
I/flutter (24043): initSupabase DONE
I/flutter (24043): Upsert START
I/flutter (24043): Upsert ERROR: PostgrestException(message: new row violates row-level security policy for table "users", code: 42501, details: Unauthorized, hint: null)

问题

请问需要修改UPDATE策略或Flutter代码中的哪部分,才能让UPSERT正常工作?


解决方案

核心原因

Supabase的UPSERT是INSERT + UPDATE的组合操作:目标行不存在时执行INSERT,存在时执行UPDATE。你的INSERT策略正常,但UPDATE策略的权限限制导致UPDATE分支触发RLS错误。

具体修复步骤

  1. 检查并调整UPDATE策略
    UPSERT执行UPDATE分支时,会触发UPDATE策略的USING(控制哪些行可被更新)和WITH CHECK(控制更新后的数据是否合规)检查。
    若你的UPDATE策略仅允许用户修改关联自身的行(比如基于auth.uid()),匿名用户无用户ID,自然无法匹配。需修改策略允许匿名用户通过id_rc1匹配目标行:

    -- 示例:允许匿名用户更新指定id_rc1的行,且仅修改version字段
    CREATE POLICY "Anonymous update users by id_rc1" ON public.users
    FOR UPDATE 
    USING (true) -- 或更严格的条件:id_rc1 = current_setting('request.jwt.claims')::json->>'id_rc1'(若前端传递标识)
    WITH CHECK (version IS NOT NULL); -- 确保更新的字段符合要求
    
  2. 验证策略覆盖场景
    UPSERT会同时触发INSERT和UPDATE的策略检查(即使其中一个分支不执行),需确保:

    • INSERT策略允许匿名用户插入包含id_rc1和version的行
    • UPDATE策略允许匿名用户匹配目标id_rc1的行,且允许修改version字段
  3. 代码无需调整
    你的Flutter代码中upsert(data, onConflict: "id_rc1")的参数设置正确,无需修改。

快速测试方法

临时将UPDATE策略设置为全权限(仅用于验证):

ALTER POLICY "你的原有UPDATE策略名称" ON public.users
FOR UPDATE USING (true)
WITH CHECK (true);

重新运行测试代码,若UPSERT成功,说明问题确实出在原UPDATE策略的条件限制上,再根据业务需求调整策略的严格性即可。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 18:15:04