-- ============================================= -- 配送模块 - RLS(行级安全)与策略(按角色/用户隔离版) -- 修复说明: -- - Postgres 的 EXECUTE 只能执行「字符串」,因此 CREATE POLICY 必须包在字符串里。 -- - 本脚本使用 format($pol$ ... $pol$) 生成字符串,避免引号转义问题。 -- - 可重复执行:创建前检查 pg_policies。 -- -- 设计目标: -- 1) 关闭 UNRESTRICTED:启用 RLS,避免 API 公共可读写。 -- 2) 最小可用: -- - 配送员(delivery)只能读写自己的配送员档案、以及自己的任务。 -- - 管理员/分析员(admin/analytics)可读取全量数据用于后台与分析。 -- - 其他角色默认无权限。 -- -- 前置假设: -- - public.ak_users 表存在,且字段:id(UUID), role(TEXT) -- - ml_delivery_drivers.user_id 可与 auth.uid() 对齐 -- ============================================= -- 0) 开启 RLS ALTER TABLE public.ml_delivery_drivers ENABLE ROW LEVEL SECURITY; ALTER TABLE public.ml_delivery_tasks ENABLE ROW LEVEL SECURITY; -- ========================= -- ml_delivery_drivers 策略 -- ========================= DO $$ BEGIN -- 1.1 配送员只能查看自己的档案 IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ml_delivery_drivers' AND policyname='delivery_can_select_own_driver_profile' ) THEN EXECUTE format($pol$ CREATE POLICY delivery_can_select_own_driver_profile ON public.ml_delivery_drivers FOR SELECT USING ( auth.role() = 'authenticated' AND user_id = auth.uid() AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = auth.uid() AND u.role = 'delivery' ) ) $pol$); END IF; -- 1.2 配送员只能更新自己的档案 IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ml_delivery_drivers' AND policyname='delivery_can_update_own_driver_profile' ) THEN EXECUTE format($pol$ CREATE POLICY delivery_can_update_own_driver_profile ON public.ml_delivery_drivers FOR UPDATE USING ( auth.role() = 'authenticated' AND user_id = auth.uid() AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = auth.uid() AND u.role = 'delivery' ) ) WITH CHECK ( user_id = auth.uid() ) $pol$); END IF; -- 1.3 管理员/分析员可读全量(后台管理/报表) IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ml_delivery_drivers' AND policyname='admin_analytics_can_select_all_delivery_drivers' ) THEN EXECUTE format($pol$ CREATE POLICY admin_analytics_can_select_all_delivery_drivers ON public.ml_delivery_drivers FOR SELECT USING ( auth.role() = 'authenticated' AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = auth.uid() AND u.role IN ('admin','analytics') ) ) $pol$); END IF; -- 1.4 管理员可写全量(派单/改派/纠错) IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ml_delivery_drivers' AND policyname='admin_can_manage_delivery_drivers' ) THEN EXECUTE format($pol$ CREATE POLICY admin_can_manage_delivery_drivers ON public.ml_delivery_drivers FOR ALL USING ( auth.role() = 'authenticated' AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = auth.uid() AND u.role = 'admin' ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = auth.uid() AND u.role = 'admin' ) ) $pol$); END IF; END $$; -- ========================= -- ml_delivery_tasks 策略 -- ========================= DO $$ BEGIN -- 2.1 配送员只能查看自己的任务 IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ml_delivery_tasks' AND policyname='delivery_can_select_own_tasks' ) THEN EXECUTE format($pol$ CREATE POLICY delivery_can_select_own_tasks ON public.ml_delivery_tasks FOR SELECT USING ( auth.role() = 'authenticated' AND EXISTS ( SELECT 1 FROM public.ml_delivery_drivers d JOIN public.ak_users u ON u.id = auth.uid() WHERE u.role = 'delivery' AND d.user_id = auth.uid() AND d.id = public.ml_delivery_tasks.driver_id ) ) $pol$); END IF; -- 2.2 配送员只能更新自己的任务 IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ml_delivery_tasks' AND policyname='delivery_can_update_own_tasks' ) THEN EXECUTE format($pol$ CREATE POLICY delivery_can_update_own_tasks ON public.ml_delivery_tasks FOR UPDATE USING ( auth.role() = 'authenticated' AND EXISTS ( SELECT 1 FROM public.ml_delivery_drivers d JOIN public.ak_users u ON u.id = auth.uid() WHERE u.role = 'delivery' AND d.user_id = auth.uid() AND d.id = public.ml_delivery_tasks.driver_id ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.ml_delivery_drivers d WHERE d.user_id = auth.uid() AND d.id = public.ml_delivery_tasks.driver_id ) ) $pol$); END IF; -- 2.3 管理员/分析员可读全量任务 IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ml_delivery_tasks' AND policyname='admin_analytics_can_select_all_delivery_tasks' ) THEN EXECUTE format($pol$ CREATE POLICY admin_analytics_can_select_all_delivery_tasks ON public.ml_delivery_tasks FOR SELECT USING ( auth.role() = 'authenticated' AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = auth.uid() AND u.role IN ('admin','analytics') ) ) $pol$); END IF; -- 2.4 管理员可写全量任务 IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ml_delivery_tasks' AND policyname='admin_can_manage_delivery_tasks' ) THEN EXECUTE format($pol$ CREATE POLICY admin_can_manage_delivery_tasks ON public.ml_delivery_tasks FOR ALL USING ( auth.role() = 'authenticated' AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = auth.uid() AND u.role = 'admin' ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = auth.uid() AND u.role = 'admin' ) ) $pol$); END IF; END $$; -- 完成 SELECT 'delivery RLS policies applied' AS message;