Просмотр исходного кода

fix(B-69): /api/mind/** 匿名白名单移除——4 端点移入 LOGIN_REQUIRED_PATHS 强制登录(401)

O-21 裁决落码(B-69 P1,连续 18 轮匿名可达):
- JwtInterceptor.java:/api/mind/alert/active、/api/mind/alert/checkin-alerts、
  /api/mind/traditional/mirror、/api/mind/traditional/compatibility 从 PUBLIC_PATHS
  移除,整族以 /api/mind/ 前缀移入 LOGIN_REQUIRED_PATHS(与 /api/health/plan/、
  /api/xiaomi-health/、/api/huawei-health/ 同族口径)。
- 匿名(无 token)访问 /api/mind/** 直接 401(writeUnauthorized),不再匿名
  (userId=-1)放行到 controller 走业务 200/400 口径漂移。
- MindFortuneControllerTest 断言改 status().isUnauthorized() + $.code==401,
  匹配拦截器 writeUnauthorized 实际返回口径(HTTP 401 + {"code":401})。

验证:
- mvn -Dtest=MindFortuneControllerTest test → Tests run: 1, Failures: 0(BUILD SUCCESS)
  日志证据:请求 /api/mind/fortune 需登录但无Token,拒绝 → 响应 401
- mvn -Dtest='JwtInterceptor*,ScG06JwtGuardTest' test → Tests run: 70, Failures: 0(全绿,
  含参数化 JwtInterceptorLoginRequiredPathTest 32 例)
E2E Test Bot 2 дней назад
Родитель
Сommit
63cf7455af

+ 3 - 4
cfc-backend/src/main/java/com/etotem/cfc/config/JwtInterceptor.java

@@ -76,10 +76,6 @@ private static final String[] PUBLIC_PATHS = {
          "/api/activity/detail",
          "/api/activity/order/notify",
          "/api/content-sections/visible",
-         "/api/mind/alert/active",
-         "/api/mind/alert/checkin-alerts",
-         "/api/mind/traditional/mirror",
-         "/api/mind/traditional/compatibility",
          "/api/mcp/**"
      };
 
@@ -115,6 +111,9 @@ private static final String[] PUBLIC_PATHS = {
         "/api/health/checkin/",             // 健康打卡:成员私有数据
         "/api/xiaomi-health/",              // 小米运动健康:OAuth 授权绑定/同步/撤销,成员私有凭证与数据
         "/api/huawei-health/",              // 华为运动健康:OAuth 授权绑定/同步/撤销,成员私有凭证与数据,必须登录(与 xiaomi-health 对齐)
+        // B-69(O-21 裁决):/api/mind/** 移出匿名白名单——运势/情绪预警/传统测试均为成员私有数据,
+        // 匿名(userId=-1)此前被 PUBLIC_PATHS 放行直通业务层(200/400 口径漂移),整族必须登录,无 token 直接 401。
+        "/api/mind/",                       // 心理解读:今日运势/情绪预警/传统测试/筛查/亲子画像,成员私有数据,必须登录
         "/api/tasks/",                      // 任务:家庭私有数据(今日/历史/审核/完成)
         "/api/energy/",                     // 五维能量:用户私有数据(sandbox/logs/grant/score-history...)
         "/api/wishes/",                     // 心愿:家庭私有数据

+ 5 - 2
cfc-backend/src/test/java/com/etotem/cfc/integration/controller/mind/MindFortuneControllerTest.java

@@ -18,8 +18,11 @@ class MindFortuneControllerTest {
 
     @Test
     void testGetTodayFortuneWithoutAuth() throws Exception {
+        // B-69(O-21 裁决):/api/mind/** 已从 PUBLIC_PATHS 移入 LOGIN_REQUIRED_PATHS,
+        // 匿名(无 token)访问直接由 JwtInterceptor 返回 HTTP 401(writeUnauthorized 写 401 + {"code":401}),
+        // 不再匿名(userId=-1)放行到 controller 后走"业务 400/500"口径漂移。
         mockMvc.perform(post("/api/mind/fortune"))
-                .andExpect(status().isOk())
-                .andExpect(jsonPath("$.code").value(401)); // JWT验证失败
+                .andExpect(status().isUnauthorized())
+                .andExpect(jsonPath("$.code").value(401)); // B-69:/api/mind/ 强制登录,匿名 401
     }
 }