Files
medical-mall/pages/mall/analytics/test/03_delivery_rls_policies.sql
2026-01-30 16:17:13 +08:00

223 lines
6.7 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================
-- 配送模块 - 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;