research.md 5.1 KB

技术调研:商家门店分管账号

1. 账号存储方案

决策

分管账号继续存放在 info_user,使用新的 user_type=5 表示“商家分管账号”,并通过 merchant_owner_id 关联唯一的商家主账号。

依据

  • 商家端登录、JWT、Redis 会话、CID、语言和消息归属都以 InfoUser.userId 为中心,复用 info_user 可以保持现有认证与推送链路。
  • 平台商家页固定传 userType=1,Mapper 使用 user_type = #{userType};类型 5 天然不会进入商家列表、导出和商家数量统计。
  • user_type=4 已用于摊位商家,不能复用。

否决方案

  • 分管账号仍使用 user_type=1,另加角色字段:所有按 user_type=1 统计、审核和导出的查询都必须额外排除分管账号,漏改一个入口就会污染平台商家管理。
  • 单独建立完整账号表:需要复制登录、Token、CID、语言和消息体系,认证链路复杂且容易产生两套用户主键。

2. 双重停用状态

决策

  • 复用 info_user.status 作为平台控制状态:0=正常、1=平台停用。
  • 新增 subaccount_status 作为主账号控制状态:0=启用、1=主账号停用,只对类型 5 生效。
  • 分管账号可用条件为:自身未删除、平台状态正常、主账号控制状态正常、所属主账号未删除且平台状态正常。

原因

如果主账号和平台共用一个可写状态,主账号可以重新启用平台强制停用的账号。两个状态必须独立,并由不同接口控制。

3. 店铺授权模型

决策

新增 merchant_subaccount_store 多对多关联表。授权保存时同时校验:分管账号的 merchant_owner_id 等于 pos_store.user_id。

原因

一个分管账号可负责多个店铺,一个店铺也可配置多个分管账号;JSON、逗号字符串或 info_user.store_id 都不能可靠表达该关系。

4. 权限校验边界

决策

在 ruoyi-system 建立统一的 MerchantStoreAccessService,每次业务请求从数据库读取当前账号和目标数据的真实门店归属:

  • 主账号可访问 pos_store.user_id = 当前账号 的全部门店。
  • 分管账号只可访问关联表中的有效门店。
  • 订单以 pos_order.md_id、商品以 pos_food.md_id、分类和规格以其实际关联商品或门店为准。
  • 新增店铺、分管账号管理、支付配置、结算和提现必须调用 requireOwner。

不把店铺集合写入 Token,也不依赖前端传入的主账号 ID,因此撤销授权后下一次请求立即生效。

5. 平台呈现

决策

不新增顶级“商家”行或独立商家审核流程。在平台 sjuser.vue 的主商家操作区增加“分管账号”入口,以对话框/抽屉展示该主账号的下属账号。

平台可以修改 info_user.status 以强制停用或恢复,但不能修改 subaccount_status、密码或店铺授权。

6. 在线状态与通知资格

决策

  • 平台“在线”状态:Redis 中存在该账号的商家 App 或 PC 有效会话。
  • 外部推送资格:账号满足全部启用条件、拥有目标店铺授权、存在商家 App 有效会话且 CID 非空。
  • 任一可接收分管账号存在时,消息分别归属这些账号,主账号不重复接收。
  • 没有可接收分管账号时,消息归属主账号并尝试主账号推送。
  • 外部推送按 CID 去重;站内消息仍按账号分别入库。

商家登录成功时更新 last_login_at。停用账号时删除其商家 App/PC Redis 会话;分管账号的每次业务请求仍重新检查数据库状态,不能只依赖会话存在。

7. 现有代码风险与兼容措施

  • InfoUserController.shanglodeing 当前允许类型 1、3、4,且没有校验 status。实现时加入类型 5,并在签发 Token 前统一执行账号可用性检查。
  • PosStoreController.addmendian、PosFoodController.setposfood 等有效商家端写入口存在未声明 token 或信任请求体归属字段的情况。实现时按 Controller 规范补充 @RequestHeader String token,并从 Token 解析操作者。
  • 平台商家列表、导出、统计仍使用 user_type=1,新增回归测试证明类型 5 不会出现或计数。
  • user_type=4 的摊位逻辑、类型 3 的夜市逻辑保持不变;不能把分管账号塞入现有单店 store_id 规则。
  • 当前工作区已有订单状态和推送调整,实施时必须在其基础上接入通知路由,不能覆盖或回退这些未提交改动。

8. 安全要求

  • 新接口使用明确 DTO 和 @RequestBody,App token 使用 @RequestHeader,不使用 Map 接收请求。
  • 手机号、名称、密码和店铺 ID 集合在 Controller/Service 中显式校验;错误使用现有国际化机制。
  • 密码沿用现有商家端 RSA 传输与存储兼容方式,禁止记录明文、密文或 Token。
  • 所有 Mapper 使用参数绑定,不拼接用户输入 SQL。
  • 批量授权在事务内完成;任一店铺越权时整体回滚。
  • 通过实体真实归属校验订单、商品和退款,防止 IDOR(越权直接对象访问)。