生成时间: 2026-08-03 · 数据来源: xnybw平台需求及工作计划.xlsx(南网在线绿能云缺陷跟踪表)· 仅针对 backup730/730backup 分支代码

Row 70:关联规划项目列表应按登录人电话匹配过滤,但实际未生效,每个账号都能看到大量测试项目

一般 2.1.待开发 全部类型 五区 模块:项目信息填报 / - 处理人:未指派

1基本信息

问题描述关联规划项目列表,要根据当前登录人的账号匹配规划项目的联系人电话,但是现在每个人的账号都展示了很多测试项目,这些测试项目匹配不上的也要隐藏。
所属模块项目信息填报 / -
涉及类型全部类型
提出人文日明
处理人 / 状态未指派 / 2.1.待开发

2问题截图

关联规划项目弹窗-大量测试项目列表
图1:"关联规划项目"弹窗,未做任何筛选条件即返回共67条记录,第4页仍全部是"测试验证-TEST#-..."开头的测试数据,未按当前登录人过滤

本表 Row 2(已关闭)曾记录同一入口"没有做权限控制",处理结论是"需要根据规划项目信息中的联系人电话字段与当前登录人电话进行匹配";本条 Row 70 表明该匹配在当前 planRelationSelector.vue 入口实际并未真正生效。

3旧代码定位(backup730 / 730backup 分支)

① 前端查询参数 —— xnybw5f@backup730:src/views/projectNew/components/baseInfo/dialog/planRelationSelector.vue 第 340 行起 searchForm 定义,以及第 388 行重置逻辑,均只包含省份/地市/类型/电压等级/项目容量/关键词等条件,不包含任何 iphone/电话字段;第 290 行 prop="iphone" 仅用于结果表格展示一列(且已被后端脱敏为 ***********),并非查询入参。

② 后端接口 —— xnybw5b@730backup:src/main/java/cn/csg/so/oms/in/newenergy/project/controller/NePcPspNewNodeController.java 第 65-77 行:

@PostMapping("/getApplicationDataList")
public IPage<NePcPspGridAppVO> getApplicationDataList(
        @ApiParam(value = "查询参数", required = true) @RequestBody PcPspParam pcPspParam) {
    if (pcPspParam != null && pcPspParam.getCreateTimeArr() != null && pcPspParam.getCreateTimeArr().size() > 0) {
        pcPspParam.setStartTime(pcPspParam.getCreateTimeArr().get(0));
        if (pcPspParam.getCreateTimeArr().size() > 1) {
            pcPspParam.setEndTime(pcPspParam.getCreateTimeArr().get(1));
        }
    }
    return nePcPspNewGridApplicationFacade.getApplicationDataList(pcPspParam);   // 第76行:直接透传前端传来的 pcPspParam,从未注入当前登录人电话
}

③ 查询 SQL —— src/main/resources/.../dbconfig/NePcPspGridAppSQL_mysql.xml:NePcPspGridAppVO_selectApplicationPage(约第90行起):

<if test="iphone!=null and iphone!=''">
    and IPHONE = #{iphone}          <!-- 只有 iphone 非空时才生效,是一个"选填"过滤条件而非强制条件 -->
</if>
根因说明:
电话过滤链路"两头都没接上":前端 searchForm 从未携带当前登录人的电话号码,后端 Controller 也从未从认证上下文中取出当前用户电话并写入 pcPspParam.setIphone(...);SQL 里的 IPHONE = #{iphone} 又被设计成"传了才生效"的可选条件(<if test="iphone!=null and iphone!=''">)。三者叠加的结果是:iphone 参数在这条链路上永远是空值,过滤条件形同虚设,因此不论哪个账号打开"关联规划项目"弹窗,看到的都是全部测试+正式数据的并集(截图中67条)。
项目内已有可复用的"按登录人查电话"方法:本仓库 src/main/java/cn/csg/so/oms/in/newenergy/project/appservice/SjbwAppService.java 第 2328、2421 行已有现成用法:commonUserUtil.getUserPhonesByUserId(UserUtils.getUser().getUserId()),用于按当前登录用户 ID 查询其绑定手机号,本次修复可直接复用该方法,无需新增查询逻辑。
这也是项目 CLAUDE.md 安全编码基线明确要求的场景:"互联网接口中'当前登录用户'身份一律由后端从认证上下文获取"——本条恰好是一处该原则被遗漏的实例:电话号码本应由后端注入而非依赖前端传参。

4修复方案

修复代码文件:NePcPspNewNodeController.java 第 65-77 行,在调用 facade 之前,由后端从认证上下文强制注入当前登录人电话,忽略/覆盖任何前端传来的 iphone 字段,防止越权查询他人电话对应的项目:

@PostMapping("/getApplicationDataList")
public IPage<NePcPspGridAppVO> getApplicationDataList(
        @ApiParam(value = "查询参数", required = true) @RequestBody PcPspParam pcPspParam) {
    if (pcPspParam != null && pcPspParam.getCreateTimeArr() != null && pcPspParam.getCreateTimeArr().size() > 0) {
        pcPspParam.setStartTime(pcPspParam.getCreateTimeArr().get(0));
        if (pcPspParam.getCreateTimeArr().size() > 1) {
            pcPspParam.setEndTime(pcPspParam.getCreateTimeArr().get(1));
        }
    }
    <ins>
    // 新增:当前登录人电话由后端认证上下文获取,不信任前端传参,防止越权查询他人电话下的规划项目
    String currentUserPhone = commonUserUtil.getUserPhonesByUserId(UserUtils.getUser().getUserId());
    pcPspParam.setIphone(currentUserPhone);
    </ins>
    return nePcPspNewGridApplicationFacade.getApplicationDataList(pcPspParam);
}

需要在 NePcPspNewNodeController@Autowired 注入 CommonUserUtil(或项目中对应的工具类,参考 SjbwAppService.java 第2328行的注入方式)。

同时建议核对 NePcPspGridAppSQL_mysql.xml / NePcPspGridAppSQL_dm.xmlIPHONE = #{iphone} 的条件是否要从"选填"改为强制拼接(例如当 iphone 为空时直接返回空列表,而不是退化为无过滤),避免后续认证上下文取号异常时又退化为"全量可见"。

效果:无论前端是否传参、传了什么,"关联规划项目"列表都只会返回联系人电话与当前登录人手机号一致的规划项目,其余(含大量测试数据)项目不再展示,同时消除了一处依赖前端传参识别用户身份的安全隐患。