# 05 RLS 权限矩阵(Supabase 行级安全) 本节整理 `complete_mall_database.sql` 中的 RLS(Row Level Security)启用范围与策略意图,并给出“角色 × 表 × 操作”的矩阵化视角,便于前后端对齐。 > 说明:该库采用 Supabase 模式,常用 `auth.uid()` 获取当前登录用户的 auth id,并通过 `ak_users.auth_id` 映射到业务用户 `ak_users.id`。 --- ## 1. RLS 设计目标 - **默认拒绝**:启用 RLS 后,如果没有策略,访问会被拒绝。 - **数据隔离优先**:用户私有数据只能访问自己的行。 - **商家/用户双视角**:订单可被“买家”和“卖家”访问。 - **公共可见数据受限**:商品仅公开上架数据。 --- ## 2. 启用 RLS 的表(来自 `complete_mall_database.sql`) 脚本显式启用 RLS: - `ml_user_profiles` - `ml_user_addresses` - `ml_shopping_cart` - `ml_user_favorites` - `ml_browse_history` - `ml_user_coupons` - `ml_orders` - `ml_products` > 备注:其他表(如 `ml_categories/ml_brands/ml_shops/ml_order_items` 等)在该脚本片段中未显式启用 RLS。 --- ## 3. 核心策略模式(pattern) ### 3.1 “归属自己”的通用模式 对用户私有表(档案、地址、购物车、收藏、浏览、券)使用类似逻辑: - `SELECT/UPDATE/DELETE`:要求当前 `auth.uid()` 对应到该行的 `user_id` - `INSERT`:要求插入行的 `user_id` 也属于当前 `auth.uid()` 概念表达(伪 SQL): ```sql -- 伪表达:当前登录者只能操作 user_id 属于自己的行 auth.uid() = (select auth_id from ak_users where id = ) ``` 价值: - 前端直连 DB 时,**就算请求参数伪造 user_id**,也无法读写别人的行。 ### 3.2 “订单:买家/卖家都可访问”模式 订单 SELECT 策略允许 `auth.uid()` 属于 `user_id` 或 `merchant_id`: ```sql auth.uid() in ( select auth_id from ak_users where id in (user_id, merchant_id) ) ``` 价值: - 买家能看自己的订单 - 商家能看自己店铺相关订单(在当前“单商家订单模型”下成立) ### 3.3 “商品:公开上架,商家管理自己的”模式 - `SELECT`:仅 `status = 1` 的商品可见 - `INSERT/UPDATE/DELETE`:要求 `merchant_id` 属于当前登录商家 --- ## 4. 权限矩阵(建议口径) > 说明:此矩阵从业务语义出发描述“期望权限”。实际是否满足,还取决于: > - 是否启用 RLS > - 是否存在相应策略 > - `ak_users` 中角色定义与 `auth_id` 映射是否正确 ### 4.1 角色定义 - **Customer(消费者)**:普通用户 - **Merchant(商家)**:拥有商品与订单管理权限 - **Admin(管理员)**:平台管理(通常需要 service role 或额外策略) ### 4.2 表级矩阵(读/写) #### `ml_user_profiles` - Customer - **SELECT**:仅本人 - **INSERT/UPDATE/DELETE**:仅本人 - Merchant - 同 Customer(如果商家也是用户) - Admin - 建议:通过 service role 或单独策略可读全量 #### `ml_user_addresses` - Customer - **SELECT/INSERT/UPDATE/DELETE**:仅本人 #### `ml_shopping_cart` - Customer - **SELECT/INSERT/UPDATE/DELETE**:仅本人 #### `ml_user_favorites` / `ml_browse_history` / `ml_user_coupons` - Customer - **SELECT/INSERT/UPDATE/DELETE**:仅本人 #### `ml_orders` - Customer - **SELECT/INSERT/UPDATE/DELETE**:仅自己的订单 - Merchant - **SELECT/INSERT/UPDATE/DELETE**:仅 `merchant_id` 为自己的订单 - Admin - 建议:service role 或独立策略全量访问 #### `ml_products` - Public / Customer - **SELECT**:仅上架(`status=1`) - Merchant - **SELECT**:至少能看上架;更合理的做法是:商家能看自己所有状态商品(当前策略是否支持需核对) - **INSERT/UPDATE/DELETE**:仅自己的商品 --- ## 5. 关键前提与性能建议 ### 5.1 `ak_users.auth_id` 的唯一性与索引 由于策略频繁执行子查询: ```sql select auth_id from ak_users where id = ... ``` 建议: - 确保 `ak_users.id` 为主键(已有) - 确保 `ak_users.auth_id` 存在且唯一(建议唯一索引) ### 5.2 RLS 子查询的成本 RLS 每次查询都要执行策略表达式。若策略中大量子查询,可能带来性能压力。 可选优化方向: - 在业务表冗余 `auth_id`(空间换性能) - 使用 `security definer` 函数封装策略逻辑(需谨慎) - 确保常用过滤字段(`user_id/merchant_id/status`)有索引