# 多端、多角色登录架构设计与权限控制方案 (RFC) ## 1. 业务背景 本项目包含多个业务线(如:商城、学校管理、配送中心等)及多种用户角色(如:消费者、学生、教师、配送员等)。为减少重复开发并保持用户体验一致,各端统一共用一套登录模板。 当前面临挑战: 1. **角色误判**:新用户注册后被分配了错误的角色(如:注册商城用户却分配了学生角色)。 2. **越权访问**:RLS 策略未对角色进行细分,导致特定操作在特定角色下报 403 权限错误。 3. **分流逻辑耦合**:登录成功后的跳转逻辑分散在各页面,难以维护。 --- ## 2. 架构设计核心:解耦登录与业务角色 ### 2.1 统一身份中心 (Auth) - 依然使用 Supabase Auth 作为认证源。 - 登录仅负责:验证凭证 -> 获取 JWT -> 建立 Session。 ### 2.2 业务配置化分流 在 `utils/store.uts` 或专门的导航服务中维护角色首页映射表。 ```typescript // 路由分流映射配置 export const ROLE_HOME_PAGES = { 'admin': '/pages/mall/admin/index', 'consumer': '/pages/mall/consumer/index', 'teacher': '/pages/school/teacher/index', 'student': '/pages/school/student/index', 'delivery': '/pages/mall/delivery/index' } /** * 根据角色执行自动导航 */ export function navigateToRoleHome(role: string) { const target = ROLE_HOME_PAGES[role] || '/pages/mall/consumer/index'; uni.reLaunch({ url: target }); } ``` --- ## 3. 注册阶段的角色控制 ### 3.1 显式角色声明 注册时,根据当前所属的应用端,向 `ensureUserProfile` 传递预期的 `defaultRole`。 - **商城端注册**:默认传 `consumer` - **学校端注册**:默认传 `student` ### 3.2 修补逻辑建议 (utils/sapi.uts) 在 `insert` 进 `ak_users` 表时,必须显式包含 `role` 字段。 ```typescript const newUserData = new UTSJSONObject() newUserData.set('id', userId) newUserData.set('email', email) newUserData.set('role', finalRole) // 显式写入业务角色 ``` --- ## 4. 数据库 RLS 策略完善 (SQL 示例) ### 4.1 用户资料表 (ak_users) 确保用户只能更新自己的资料,但不能绕过逻辑修改自己的 `role`。 ```sql -- 开启 RLS ALTER TABLE ak_users ENABLE ROW LEVEL SECURITY; -- 允许用户查看自己的资料 CREATE POLICY "Users can view own data" ON ak_users FOR SELECT TO authenticated USING (auth.uid() = id); ``` ### 4.2 业务表角色锁 (以 ml_shopping_cart 为例) 只有角色为 `consumer` 的用户才能执行购物车操作。 ```sql -- 只有消费者可以插入购物车 CREATE POLICY "Only consumers can use cart" ON ml_shopping_cart FOR INSERT TO authenticated WITH CHECK ( auth.uid() = user_id AND EXISTS ( SELECT 1 FROM ak_users WHERE id = auth.uid() AND role = 'consumer' ) ); ``` --- ## 5. 迁移与修复建议 1. **现状修正**:检查 Supabase 后台 `ak_users` 表,手动或批量修改 `student` 角色的消费者用户为 `consumer`。 2. **清理缓存**:小程序环境下需清理本地 `user_id` 缓存后重新登录,以刷新受限角色。 3. **URL 规范**:建议将各端的页面放入对应的分层目录中(如 `/pages/mall/...`, `/pages/school/...`),便于权限隔离。