Kaynağa Gözat

补充商家会话统一认证设计

将 JWT、有效期与 Redis 会话校验收口到认证层,并明确 Controller 仅负责身份取值和业务归属校验。
qmj 2 saat önce
ebeveyn
işleme
ce3ac74832

+ 3 - 0
specs/022-merchant-store-subaccounts/plan.md

@@ -130,6 +130,7 @@ E:/QtwCode/foodie/foodie-admin-vue/src/api/language/language.vi.js
 3. 扩展 `shanglodeing` 支持类型 5,签发 Token 前检查自身与主账号状态,更新最后登录时间。
 4. 增加商家退出接口;停用或重置密码时删除 App/PC 会话。
 5. 回归平台 `userType=1` 列表、导出和统计,证明类型 5 不出现、不计数、不进入审核。
+6. 扩展 `@Auth` 支持显式启用 Redis 会话认证;商家业务接口在认证切面统一完成 JWT 与 JTI 校验,Controller 不再调用会话服务二次认证。
 
 ### Phase 3:店铺、商品和订单数据权限
 
@@ -160,6 +161,7 @@ E:/QtwCode/foodie/foodie-admin-vue/src/api/language/language.vi.js
 3. 构建 `foodie-store` 与 `foodie-admin-vue`。
 4. 按 `quickstart.md` 执行越权、双重停用、通知全发和主账号兜底场景。
 5. 检查三个仓库的暂存范围、换行和差异;SQL 只保留在迁移文档。
+6. 增加认证切面定向测试,覆盖有效会话放行、Redis 会话缺失拒绝、未启用会话选项时保持现有非商家接口行为,并回归商家店铺及订单入口。
 
 ## 测试文件规划
 
@@ -189,3 +191,4 @@ ruoyi-admin/src/test/java/com/ruoyi/app/order/DeliveryOrderNotificationServiceTe
 | 双重状态 | 平台强制停用不能被主账号覆盖 | 共用一个状态无法区分操作者和恢复权限 |
 | 集中权限服务 | 多个旧 Controller 的归属规则不同,必须统一防止 IDOR | 仅前端隐藏或各 Controller 手写条件容易漏改 |
 | 通知路由服务 | 同店多接收者、消息逐账号归属、主账号兜底需要统一行为 | 在每个订单入口复制循环会产生规则漂移 |
+| `@Auth` 可选会话认证 | 在不改变骑手、普通用户认证行为的前提下,把商家 JWT 与 Redis 会话校验集中到 Controller 之前 | 全局强制 Redis 校验会扩大兼容性影响;Controller 手工调用会产生重复认证和遗漏风险 |

+ 3 - 0
specs/022-merchant-store-subaccounts/spec.md

@@ -152,6 +152,8 @@
 - **FR-033**:平台不得修改分管账号的店铺授权或密码;这些能力只属于该账号的主账号。
 - **FR-034**:主商家被平台停用时,系统必须同时禁止其全部分管账号登录、访问商家业务和接收店铺通知。
 - **FR-035**:平台现有商家新增、修改和审核入口不得创建分管账号或把普通账号转换为分管账号。
+- **FR-036**:商家业务接口的 JWT 签名、有效期和 Redis 会话存在性必须在进入 Controller 前由统一认证层完成,不得由各 Controller 重复执行会话认证。
+- **FR-037**:Controller 只能使用统一认证通过后的 Token 身份执行门店、订单、商品等业务归属校验;会话服务只负责退出、批量撤销和在线状态查询。
 
 ### 关键实体
 
@@ -175,6 +177,7 @@
 - **SC-007**:同一通知的单个接收账号推送失败时,其他符合条件账号仍能完成消息入库和推送尝试。
 - **SC-008**:任意数量的分管账号都不会改变平台商家列表、导出和商家数量统计中的主商家数量。
 - **SC-009**:平台强制停用后,主账号无法绕过该状态重新启用分管账号,相关登录、业务访问和通知测试拦截率达到 100%。
+- **SC-010**:缺少、过期、签名错误或 Redis 会话不存在的商家 Token 均在进入 Controller 前被拒绝;有效 App/PC 商家 Token 只执行一次集中会话认证并可正常进入业务处理。
 
 ## 假设
 

+ 23 - 0
specs/022-merchant-store-subaccounts/tasks.md

@@ -338,6 +338,7 @@ T001 -> T002 -> T003 -> T004 -> T005
                                         |
 T004 --------------------------------> T010
 T001..T010 --------------------------> T011
+T005..T007 --------------------------> T012
 ```
 
 - T001、T002 是所有业务故事的阻塞基础。
@@ -355,3 +356,25 @@ T001..T010 --------------------------> T011
 | FR-024、FR-025、FR-026、FR-027 | T007、T009、T011 |
 | FR-028、FR-029、FR-030、FR-031、FR-032、FR-033、FR-034、FR-035 | T004、T005、T010 |
 | SC-001、SC-002、SC-003、SC-004、SC-005、SC-006、SC-007、SC-008、SC-009 | T003~T011 |
+| FR-036、FR-037、SC-010 | T012 |
+
+---
+
+## Phase 7:统一商家会话认证
+
+### T012 将商家 Redis 会话校验收口到认证层
+
+**文件:**
+
+- 修改:`ruoyi-system/src/main/java/com/ruoyi/system/utils/Auth.java`
+- 修改:`ruoyi-system/src/main/java/com/ruoyi/system/utils/AuthAspect.java`
+- 修改:`ruoyi-admin/src/main/java/com/ruoyi/app/user/MerchantTokenSessionService.java`
+- 修改:当前调用 `MerchantTokenSessionService.requireUserId` 的商家 Controller
+- 新增或修改:认证切面、商家店铺和商家订单定向测试
+
+- [ ] 先写认证切面测试,覆盖启用会话校验时有效 JTI 放行、缺失 JTI/Redis Key 拒绝,以及默认 `@Auth` 不增加 Redis 会话要求;运行并确认 RED。
+- [ ] 为 `@Auth` 增加默认关闭的会话校验选项,由 `AuthAspect` 在 JWT 校验通过后检查 JTI 对应 Redis Key,并使用现有国际化登录失效错误。
+- [ ] 商家业务入口显式启用会话校验,删除 Controller 对 `MerchantTokenSessionService.requireUserId` 的调用;Controller 只从已验证 Token 获取登录用户 ID 并继续执行目标实体归属校验。
+- [ ] `MerchantTokenSessionService` 删除身份认证职责,只保留退出当前会话、撤销账号全部 App/PC 会话和在线状态查询。
+- [ ] 运行认证切面、商家登录、店铺和订单定向测试,并使用 JDK 21 构建 `ruoyi-admin` 及依赖模块。
+- [ ] 检查 `git diff --check`、暂存文件清单和测试结果,形成独立中文提交并推送当前分支。