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

Supabase配置角色鉴权策略报无限递归的解决方法

问题根因

你遇到的无限递归报错是RLS(行级安全)的典型触发场景:
你写的策略中使用子查询查询users表判断当前用户是否为admin,而users表本身开启了RLS,执行这个子查询时会再次触发RLS规则校验,又要执行一遍同一个子查询,形成无限调用循环最终报错。
核心禁忌:不要在某张表的RLS策略中,直接写子查询查询这张开启了RLS的表本身,必然触发递归。

可行解决方案

方案1:基于JWT自定义声明判断(性能最优,最推荐)

Supabase登录后返回的JWT中会携带auth.users表的raw_app_meta_data字段内容,你可以直接把用户角色存在这个字段里,查询时直接读JWT值,完全不需要查public.users表,从根源避免递归:

  • 创建/更新用户时,将角色写入auth.users.raw_app_meta_data,例如给管理员用户添加{"role": "admin"}元数据
  • 给public.users表配置SELECT类型的RLS策略,表达式如下:
(auth.jwt() ->> 'role' = 'admin') AND (role = 'agent')

这个策略的逻辑是:当前登录用户JWT中携带的角色为admin时,仅允许查询role字段值为agent的行,完全没有表查询操作,性能最高也不会触发递归。

方案2:使用security definer函数封装角色查询(适配角色存在public.users表的场景)

如果你已经把角色存在public.users表中、不想调整存储位置,可以创建一个带security definer属性的函数获取当前用户角色,这类函数以函数创建者(默认为postgres超级管理员)的权限执行,会绕过RLS校验,不会触发递归:

  1. 执行SQL创建角色查询函数:
create or replace function public.get_current_user_role()
returns text
language sql
stable
security definer set search_path = public
as $$
  select role from public.users where email = auth.email() limit 1;
$$;
  1. 给已登录的普通用户开放函数执行权限:
grant execute on function public.get_current_user_role() to authenticated;
  1. 配置SELECT类型的RLS策略,表达式如下:
(public.get_current_user_role() = 'admin') AND (role = 'agent')
额外注意事项
  • 不要在public.users表中存储明文密码,Supabase Auth模块已经在auth.users表中存储了加盐加密后的用户密码,public表存明文会有严重的数据泄露风险
  • 要确保public.users.email字段的值和auth.users.email完全一一对应,否则会出现角色判断错误的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:54:22