# 贷款定价敏感字段加密后端实施记录

## 修改内容
- 在 `ruoyi-loan-pricing` 新增 `SensitiveFieldCryptoService`，统一处理 `custName`、`idNum` 的 AES/ECB/PKCS5Padding + Base64 加解密。
- 在 `ruoyi-loan-pricing` 新增 `LoanPricingSensitiveDisplayService`，统一处理个人姓名、企业名称、身份证号、统一社会信用代码的脱敏展示。
- 在 `LoanPricingWorkflowServiceImpl` 的创建链路对 `custName`、`idNum` 加密后入库，并在列表、详情链路解密后做脱敏返回。
- 在 `LoanPricingWorkflowServiceImpl` 的详情链路补充对 `ModelRetailOutputFields`、`ModelCorpOutputFields` 基本信息中的 `custName`、`idNum` 进行脱敏，避免模型输出区域继续暴露明文。
- 在 `LoanPricingModelService` 调用模型前显式解密 `custName`、`idNum`，保证模型入参不接收密文；同时补齐 `ModelInvokeDTO.idNum` 字段。
- 修复模型调用后更新 `modelOutputId` 时把解密后的 `custName`、`idNum` 明文回写数据库的问题，改为仅更新 `modelOutputId`。
- 在 `LoanPricingWorkflowMapper.xml` 和服务查询条件中移除按 `custName` 查询，改为按 `custIsn` 查询。
- 新增 `sql/clear_loan_pricing_workflow_history.sql`，用于清理贷款定价流程及模型输出历史数据。

## 新增测试
- `SensitiveFieldCryptoServiceTest`
- `LoanPricingSensitiveDisplayServiceTest`
- `LoanPricingWorkflowServiceImplTest`
- `LoanPricingModelServiceTest`

## 验证结果
- 执行 `mvn -pl ruoyi-loan-pricing -am -Dtest=SensitiveFieldCryptoServiceTest,LoanPricingSensitiveDisplayServiceTest -Dsurefire.failIfNoSpecifiedTests=false test`，结果通过。
- 执行 `mvn -pl ruoyi-loan-pricing -am -Dtest=LoanPricingWorkflowServiceImplTest -Dsurefire.failIfNoSpecifiedTests=false test`，结果通过。
- 执行 `mvn -pl ruoyi-loan-pricing -am -Dtest=LoanPricingWorkflowServiceImplTest,LoanPricingModelServiceTest -Dsurefire.failIfNoSpecifiedTests=false test`，结果通过。
- 执行 `mvn -pl ruoyi-loan-pricing -am -Dtest=SensitiveFieldCryptoServiceTest,LoanPricingSensitiveDisplayServiceTest,LoanPricingWorkflowServiceImplTest,LoanPricingModelServiceTest -Dsurefire.failIfNoSpecifiedTests=false test`，结果通过。
- 执行 `mvn -pl ruoyi-loan-pricing -am -Dsurefire.failIfNoSpecifiedTests=false test`，结果通过。
- 从根工程重新打包 `ruoyi-admin.jar` 后，以 `18080` 端口启动临时后端实例，并将 `model.url` 指向 `http://localhost:18080/rate/pricing/mock/invokeModel` 完成联调。
- 个人流程与企业流程创建成功，接口即时返回的 `custName`、`idNum` 为密文。
- 调用参数错误场景 `/loanPricing/workflow/create/personal` 且缺少 `custIsn`，接口返回 `500`，错误信息为“客户内码不能为空”。
- 调用列表接口按 `custIsn` 查询，确认个人返回 `custName` 为 `张*`，企业返回 `custName` 为 `测试****公司`。
- 调用详情接口，确认流程主信息中个人返回 `张* / 1101********1234`，企业返回 `测试****公司 / 91*************00X`。
- 调用详情接口，确认模型输出“基本信息”中个人返回 `张* / 3301********1234`，企业返回 `北京******公司 / 91*************XXX`。

## 备注
- 联调过程中发现 `serialNum` 仍使用毫秒时间戳生成，并发创建可能触发 `uk_serial_num` 冲突；该问题为本次验证中暴露的既有风险，本次未纳入敏感字段加密方案范围内处理。
