Files
medical-mall/doc_mall/consumer/MULTI_ROLE_LOGIN_ARCHITECTURE.md

3.2 KiB
Raw Blame History

多端、多角色登录架构设计与权限控制方案 (RFC)

1. 业务背景

本项目包含多个业务线(如:商城、学校管理、配送中心等)及多种用户角色(如:消费者、学生、教师、配送员等)。为减少重复开发并保持用户体验一致,各端统一共用一套登录模板。

当前面临挑战:

  1. 角色误判:新用户注册后被分配了错误的角色(如:注册商城用户却分配了学生角色)。
  2. 越权访问RLS 策略未对角色进行细分,导致特定操作在特定角色下报 403 权限错误。
  3. 分流逻辑耦合:登录成功后的跳转逻辑分散在各页面,难以维护。

2. 架构设计核心:解耦登录与业务角色

2.1 统一身份中心 (Auth)

  • 依然使用 Supabase Auth 作为认证源。
  • 登录仅负责:验证凭证 -> 获取 JWT -> 建立 Session。

2.2 业务配置化分流

utils/store.uts 或专门的导航服务中维护角色首页映射表。

// 路由分流映射配置
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)

insertak_users 表时,必须显式包含 role 字段。

const newUserData = new UTSJSONObject()
newUserData.set('id', userId)
newUserData.set('email', email)
newUserData.set('role', finalRole) // 显式写入业务角色

4. 数据库 RLS 策略完善 (SQL 示例)

4.1 用户资料表 (ak_users)

确保用户只能更新自己的资料,但不能绕过逻辑修改自己的 role

-- 开启 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 的用户才能执行购物车操作。

-- 只有消费者可以插入购物车
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/...),便于权限隔离。