223 lines
6.7 KiB
SQL
223 lines
6.7 KiB
SQL
-- =============================================
|
||
-- 配送模块 - 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;
|