160 lines
4.4 KiB
Markdown
160 lines
4.4 KiB
Markdown
# 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 = <row.user_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`)有索引
|