-- ===================================================== -- 修复RLS策略无限递归错误 -- 解决 "infinite recursion detected in policy" 错误 -- ===================================================== -- 第一步:删除所有可能导致递归的策略 DO $$ DECLARE r RECORD; BEGIN RAISE NOTICE '🧹 删除可能导致递归的策略'; -- 删除所有消息相关表的策略 FOR r IN SELECT schemaname, tablename, policyname FROM pg_policies WHERE schemaname = 'public' AND tablename IN ('ak_messages', 'ak_message_recipients', 'ak_message_groups', 'ak_message_group_members', 'ak_message_templates', 'ak_user_message_preferences', 'ak_message_stats', 'ak_message_types') LOOP EXECUTE format('DROP POLICY IF EXISTS %I ON %I.%I', r.policyname, r.schemaname, r.tablename); RAISE NOTICE ' 删除策略: %.%', r.tablename, r.policyname; END LOOP; RAISE NOTICE '✅ 策略清理完成'; END $$; -- 第二步:重新创建安全的策略(避免递归) -- 启用RLS ALTER TABLE public.ak_message_types ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_messages ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_message_recipients ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_message_groups ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_message_group_members ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_message_templates ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_user_message_preferences ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ak_message_stats ENABLE ROW LEVEL SECURITY; -- 1. 消息类型策略(简单,无递归) CREATE POLICY "authenticated_can_view_message_types" ON public.ak_message_types FOR SELECT USING (auth.role() = 'authenticated'); CREATE POLICY "admins_can_manage_message_types" ON public.ak_message_types FOR ALL USING ( auth.jwt() ->> 'user_role' = 'admin' ); -- 2. 群组成员策略(修复递归问题) CREATE POLICY "users_can_view_own_membership" ON public.ak_message_group_members FOR SELECT USING ( -- 用户可以查看自己的成员记录 user_id = auth.uid() OR -- 管理员可以查看所有成员 auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "users_can_join_groups" ON public.ak_message_group_members FOR INSERT WITH CHECK ( -- 用户可以加入群组(以自己的身份) user_id = auth.uid() OR -- 管理员可以添加任何成员 auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "users_can_update_own_membership" ON public.ak_message_group_members FOR UPDATE USING ( user_id = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "users_can_leave_groups" ON public.ak_message_group_members FOR DELETE USING ( user_id = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); -- 3. 群组策略(简化,避免复杂查询) CREATE POLICY "users_can_view_public_groups" ON public.ak_message_groups FOR SELECT USING ( -- 公开群组所有人可见 is_public = true OR -- 群组创建者可见 created_by = auth.uid() OR -- 管理员可见 auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "authenticated_users_can_create_groups" ON public.ak_message_groups FOR INSERT WITH CHECK ( auth.role() = 'authenticated' AND created_by = auth.uid() ); CREATE POLICY "creators_can_update_groups" ON public.ak_message_groups FOR UPDATE USING ( created_by = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "creators_can_delete_groups" ON public.ak_message_groups FOR DELETE USING ( created_by = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); -- 4. 消息策略(简化,使用函数避免递归) -- 创建辅助函数检查群组成员身份 CREATE OR REPLACE FUNCTION public.is_group_member(group_id UUID, user_id UUID) RETURNS BOOLEAN AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM public.ak_message_group_members WHERE ak_message_group_members.group_id = is_group_member.group_id AND ak_message_group_members.user_id = is_group_member.user_id AND status = 'active' ); END; $$ LANGUAGE plpgsql SECURITY DEFINER; CREATE POLICY "users_can_view_relevant_messages" ON public.ak_messages FOR SELECT USING ( -- 用户是发送者 (sender_type = 'user' AND sender_id = auth.uid()) OR -- 用户是接收者(单用户消息) (receiver_type = 'user' AND receiver_id = auth.uid()) OR -- 广播消息所有人可见 (receiver_type = 'broadcast') OR -- 群组消息(使用函数检查,避免递归) (receiver_type = 'group' AND public.is_group_member(receiver_id, auth.uid())) OR -- 管理员可以查看所有消息 auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "users_can_send_messages" ON public.ak_messages FOR INSERT WITH CHECK ( -- 用户只能以自己的身份发送 (sender_type = 'user' AND sender_id = auth.uid()) OR -- 管理员可以发送系统消息 (sender_type = 'system' AND auth.jwt() ->> 'user_role' = 'admin') ); CREATE POLICY "users_can_update_own_messages" ON public.ak_messages FOR UPDATE USING ( (sender_type = 'user' AND sender_id = auth.uid()) OR auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "users_can_delete_own_messages" ON public.ak_messages FOR DELETE USING ( (sender_type = 'user' AND sender_id = auth.uid()) OR auth.jwt() ->> 'user_role' = 'admin' ); -- 5. 消息接收者策略 CREATE POLICY "users_can_view_own_recipients" ON public.ak_message_recipients FOR SELECT USING ( user_id = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "system_can_create_recipients" ON public.ak_message_recipients FOR INSERT WITH CHECK ( user_id = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "users_can_update_own_recipients" ON public.ak_message_recipients FOR UPDATE USING ( user_id = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); -- 6. 消息模板策略 CREATE POLICY "users_can_view_templates" ON public.ak_message_templates FOR SELECT USING ( is_public = true OR created_by = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "users_can_create_templates" ON public.ak_message_templates FOR INSERT WITH CHECK ( auth.role() = 'authenticated' AND created_by = auth.uid() ); CREATE POLICY "users_can_update_own_templates" ON public.ak_message_templates FOR UPDATE USING ( created_by = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "users_can_delete_own_templates" ON public.ak_message_templates FOR DELETE USING ( created_by = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); -- 7. 用户偏好策略 CREATE POLICY "users_can_manage_own_preferences" ON public.ak_user_message_preferences FOR ALL USING ( user_id = auth.uid() OR auth.jwt() ->> 'user_role' = 'admin' ); -- 8. 消息统计策略 CREATE POLICY "users_can_view_relevant_stats" ON public.ak_message_stats FOR SELECT USING ( (entity_type = 'user' AND entity_id = auth.uid()) OR auth.jwt() ->> 'user_role' = 'admin' ); CREATE POLICY "admins_can_update_stats" ON public.ak_message_stats FOR ALL USING ( auth.jwt() ->> 'user_role' = 'admin' ); -- 验证策略创建结果 DO $$ DECLARE policy_count INTEGER; function_count INTEGER; BEGIN RAISE NOTICE '🔍 验证策略重建结果'; -- 检查策略数量 SELECT COUNT(*) INTO policy_count FROM pg_policies WHERE schemaname = 'public' AND tablename IN ('ak_messages', 'ak_message_recipients', 'ak_message_groups', 'ak_message_group_members', 'ak_message_templates', 'ak_user_message_preferences', 'ak_message_stats', 'ak_message_types'); -- 检查辅助函数 SELECT COUNT(*) INTO function_count FROM information_schema.routines WHERE routine_schema = 'public' AND routine_name = 'is_group_member'; RAISE NOTICE '📊 重建统计:'; RAISE NOTICE ' - 策略数量: %', policy_count; RAISE NOTICE ' - 辅助函数: %', function_count; IF policy_count > 20 AND function_count > 0 THEN RAISE NOTICE '🎉 策略重建成功!递归问题已解决'; ELSE RAISE NOTICE '⚠️ 重建可能不完整,请检查'; END IF; END $$; -- 完成消息 SELECT '✅ RLS策略递归问题已修复' as status, '使用了辅助函数和简化逻辑避免递归' as message;