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

Supabase RLS策略报错‘stack depth limit exceeded’求助

解决RLS策略触发"stack depth limit exceeded"无限递归问题

问题根源

你的is_member_of函数会查询启用了RLS的user_profiles表,而RLS策略又调用这个函数。当执行查询时:

  1. 查询user_profiles触发RLS检查
  2. RLS策略调用is_member_of函数
  3. 函数再次查询user_profiles,又触发RLS检查
  4. 循环往复导致栈溢出

其他项目能正常运行,大概率是因为函数或RLS配置存在差异(比如函数绕过了RLS、表未启用RLS等)。

解决方案

方案1:查询时直接绕过RLS

修改函数,在查询user_profiles时使用WITH BYPASSRLS关键字,跳过RLS检查:

create or replace function is_member_of(_user_id uuid, _role_id bigint) 
returns boolean as $$
SELECT EXISTS (
  SELECT 1
  FROM user_profiles om WITH BYPASSRLS
  WHERE om.role_id = _role_id
  AND om.user_id = _user_id
);
$$ language sql stable;

方案2:使用SECURITY DEFINER临时关闭RLS

通过SECURITY DEFINER让函数以创建者权限执行,并临时关闭RLS:

create or replace function is_member_of(_user_id uuid, _role_id bigint) 
returns boolean as $$
BEGIN
  SET LOCAL row_security = off;
  RETURN EXISTS (
    SELECT 1
    FROM user_profiles om
    WHERE om.role_id = _role_id
    AND om.user_id = _user_id
  );
END;
$$ language plpgsql security definer stable;

-- 限制函数执行权限,仅授权给需要的用户(比如你的应用认证用户)
REVOKE ALL ON FUNCTION is_member_of(uuid, bigint) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION is_member_of(uuid, bigint) TO authenticated;

验证RLS策略

确保你的RLS策略逻辑正确,比如允许匹配指定角色的用户访问全表:

-- 先启用RLS(如果还没启用)
ALTER TABLE user_profile ENABLE ROW LEVEL SECURITY;

-- 创建全表访问策略
CREATE POLICY "Full access for matched role" ON user_profile
FOR ALL USING (is_member_of(auth.uid(), 1)); -- 替换1为你需要授权的role_id

注意事项

  • 函数需标记为stable,让PostgreSQL可以缓存结果,减少重复执行
  • 使用SECURITY DEFINER时,务必限制函数执行权限,避免安全风险
  • 确认auth.uid()能正确获取当前用户的UUID(适用于Supabase等使用auth.users的场景)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 04:35:32