Browse Source

feat(S-cfc-231): teacher.task.review 规划师任务审核补家庭归属校验使绿——GuideFamilyTaskController.reviewTask/batchReviewTasks 增加被审任务 task.familyId==路径 familyId 校验(SC-T-06/TC-T-09-P 防跨家庭越权审核 IDOR;TC-T-18-E 批量含跨家任务跳过独立不落库),checkMemberOnly 改为接收 Task 避免二次查询;GuideFamilyTaskReviewContractTest 5 例 2红→全绿

Sisyphus 3 hours ago
parent
commit
07acbee525

+ 23 - 4
cfc-backend/src/main/java/com/etotem/cfc/controller/guide/GuideFamilyTaskController.java

@@ -89,8 +89,7 @@ public class GuideFamilyTaskController {
     /**
      * 会员任务校验:task.memberOnly==1 且家庭非会员 → 拒绝(提示开通会员)
      */
-    private Result<?> checkMemberOnly(Long taskId) {
-        Task task = taskMapper.selectById(taskId);
+    private Result<?> checkMemberOnly(Task task) {
         if (task == null) {
             return Result.error("任务不存在");
         }
@@ -329,7 +328,16 @@ public class GuideFamilyTaskController {
         if (!RolesUtil.hasTeacherRole(role, roles)) { return Result.error("Access denied"); }
         Result<Void> denied = requireBound(guideId, familyId);
         if (denied != null) return Result.error(denied.getCode(), denied.getMessage());
-        Result<?> memberCheck = checkMemberOnly(taskId);
+
+        // SC-T-06/TC-T-09-P 数据隔离:被审任务必须属于路径 familyId,否则拒绝(防跨家庭越权审核 IDOR)
+        Task task = taskMapper.selectById(taskId);
+        if (task == null) {
+            return Result.error("任务不存在");
+        }
+        if (!familyId.equals(task.getFamilyId())) {
+            return Result.error(403, "任务不属于该家庭");
+        }
+        Result<?> memberCheck = checkMemberOnly(task);
         if (memberCheck != null) {
             return Result.error(memberCheck.getMessage());
         }
@@ -373,8 +381,19 @@ public class GuideFamilyTaskController {
 
         for (Long taskId : taskIds) {
             try {
+                Task task = taskMapper.selectById(taskId);
+                if (task == null) {
+                    failCount++;
+                    continue;
+                }
+                // SC-T-06/TC-T-09-P 数据隔离:被审任务必须属于路径 familyId,
+                // 跨家庭任务跳过且不进入审核(TC-T-18-E 部分失败不影响其他,各自独立不落库)
+                if (!familyId.equals(task.getFamilyId())) {
+                    failCount++;
+                    continue;
+                }
                 // 会员任务校验:审核通过会员任务需家庭为会员
-                Result<?> memberCheck = checkMemberOnly(taskId);
+                Result<?> memberCheck = checkMemberOnly(task);
                 if (memberCheck != null) {
                     failCount++;
                     continue;