|
|
@@ -7,6 +7,7 @@ import com.etotem.cfc.entity.User;
|
|
|
import com.etotem.cfc.mapper.TaskPlanInstanceMapper;
|
|
|
import com.etotem.cfc.mapper.UserMapper;
|
|
|
import com.etotem.cfc.service.PlanActivationService;
|
|
|
+import com.etotem.cfc.service.GuideFamilyAccessGuard;
|
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
|
import org.slf4j.Logger;
|
|
|
@@ -40,6 +41,10 @@ public class PlanReviewController {
|
|
|
@Resource
|
|
|
private com.etotem.cfc.service.PlannerCertificationGuard plannerCertificationGuard;
|
|
|
|
|
|
+ /** 规划师-家庭绑定统一授权判定点(全项目唯一,SC-T-13 数据隔离) */
|
|
|
+ @Resource
|
|
|
+ private GuideFamilyAccessGuard guideFamilyAccessGuard;
|
|
|
+
|
|
|
@Operation(summary = "查看家庭的方案列表")
|
|
|
@PostMapping("/family-list")
|
|
|
public Result<List<TaskPlanInstance>> listFamilyPlans(@RequestBody Map<String, Object> body,
|
|
|
@@ -62,6 +67,23 @@ public class PlanReviewController {
|
|
|
return Result.noFamily("请先创建或加入家庭");
|
|
|
}
|
|
|
}
|
|
|
+ // SC-T-13 数据隔离(teacher.data.isolation):teacher 仅可访问其绑定家庭
|
|
|
+ // (guide_families status='binding' isBound 校验,统一授权判定点 GuideFamilyAccessGuard)。
|
|
|
+ // 非绑定 familyId(含 body.familyId 越权目标)在触达方案查询层前 403 拒绝,防止 IDOR 跨家庭泄漏。
|
|
|
+ if (!"admin".equals(role)) {
|
|
|
+ Result<Void> denied;
|
|
|
+ if (guideFamilyAccessGuard != null) {
|
|
|
+ denied = guideFamilyAccessGuard.checkBinding(userId, filterFamilyId);
|
|
|
+ } else {
|
|
|
+ // 守卫不可用(如无 Spring 上下文的契约单测夹具)→ 失败关闭:收敛到 JWT 家庭,
|
|
|
+ // 请求家庭 ≠ JWT 家庭视为越权拒绝(与 isBound 对越权目标的判定一致,仅测试环境触发)
|
|
|
+ denied = filterFamilyId != null && filterFamilyId.equals(jwtFamilyId)
|
|
|
+ ? null : Result.error(403, "无权访问该家庭数据");
|
|
|
+ }
|
|
|
+ if (denied != null) {
|
|
|
+ return Result.error(denied.getCode(), denied.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
LambdaQueryWrapper<TaskPlanInstance> w = new LambdaQueryWrapper<TaskPlanInstance>()
|
|
|
.orderByDesc(TaskPlanInstance::getCreatedAt);
|
|
|
if (filterFamilyId != null) {
|