Files
medical-mall/docs/sql/05_rls_permissions_matrix.md

160 lines
4.4 KiB
Markdown
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.
# 05 RLS 权限矩阵Supabase 行级安全)
本节整理 `complete_mall_database.sql` 中的 RLSRow 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`)有索引