Files
lingniu-vehicle-ingest/vehicle-data-platform/docs/oneos-change-approval-proposal.md

10 KiB
Raw Blame History

OneOS 客户车辆门户变更审批提案

更新时间2026-07-14

状态已停止。2026-07-14 用户明确要求不修改 ln-asset-management 任何逻辑此前本地试验改动已全部撤销OneOS 仓库保持干净。本文件仅保留为风险证据,不构成待执行审批项。

1. 审批目标

本提案只解决客户只读访问车辆数据所必需的三件事:

  1. OneOS 能稳定识别客户账号并输出不可伪造的客户身份;
  2. OneOS 的“当前客户车辆”事实不会因合同保存被破坏;
  3. 车辆数据中台收到客户身份后,只能访问该客户的车辆 Scope。

车辆锁车、控车以及保险、结算、事故、违章等客户功能不在本批次范围内。

2. 当前源码证据

2.1 客户车辆 RPC 当前会泄露全量车辆

ln-asset-management/src/main/java/com/ln/asset/api/impl/RemoteVehicleServiceImpl.java:83listByCustomerId 忽略 customerId,实际只按 del_flag=0 查询。其 VO 转换也没有回填 customerIdcontractCode

该接口在修复前必须保持内部禁用,不能作为车辆数据中台的授权来源。

2.2 当前租赁 Mapper 会丢字段

ln-asset-management/src/main/resources/mapper/VehicleLeaseOrderRecordMapper.xml:6BaseResultMapBase_Column_List 缺少以下实体字段:

  • customer_idproject_name
  • delivery_vehicle_idlast_delivery_name
  • return_vehicle_task_idlast_return_name
  • update_by

使用这些自定义查询取得记录后,上述字段会变成空值。生产审计同时发现聚合记录与最新历史记录有 325 条关键字段差异,不能把空值当成“无业务关系”。

2.3 合同保存会清空交还车事实

VehicleLeaseOrderRecordServiceImpl.java:262deliveryVehicleId == null 时,同时清空交车和还车的 单据 ID、时间、里程与操作人。合同提交/更新并不代表交车事实撤销,因此这里违反业务事实的单一写入原则。

交车字段只能由交车完成/撤销流程修改;还车字段只能由还车完成/撤销流程修改。合同更新只能更新客户、合同、 项目和业务组织字段。

2.4 客户账号当前不能安全登录

  • CustomerInfoServiceImpl.java:188 先尝试创建 sys_user,之后才保存客户档案;远程调用失败被吞掉,两个库之间不存在事务一致性。
  • SysUserRegistrar.java:27 给所有业务账号使用共享初始密码 ln123456
  • RemoteUserServiceImpl.java:222 把业务账号开通绑定到公开注册开关 sys.account.registerUser
  • UserType.java:14 只支持 sys_userapp_usercustomer 会在 Sa-Token 权限解析时抛异常。
  • 密码登录按 tenantId + username 查询,短信登录默认取同手机号的第一条记录,均不能可靠区分客户账号。
  • 更新客户档案不会同步账号;删除客户时账号删除异常同样只记日志。

生产审计结果是 335 个有效客户中,当前客户账号数量为 0因此不能直接批量启用现有逻辑。

3. 推荐变更批次

B1修复客户车辆业务事实ln-asset-management

预计修改文件:

  • src/main/resources/mapper/VehicleLeaseOrderRecordMapper.xml
  • src/main/java/com/ln/asset/modules/contract/mapper/VehicleLeaseOrderRecordMapper.java
  • src/main/java/com/ln/asset/modules/contract/service/impl/VehicleLeaseOrderRecordServiceImpl.java
  • src/main/java/com/ln/asset/api/impl/RemoteVehicleServiceImpl.java
  • ln-asset-api/src/main/java/com/ln/asset/api/RemoteVehicleService.java
  • ln-asset-api/src/main/java/com/ln/asset/api/domain/vo/RemoteVehicleVo.java
  • 对应单元/集成测试文件

变更内容:

  1. 补齐 Mapper 的所有实体字段映射与列清单;禁止“读出空值再全实体更新”覆盖已有事实。
  2. 把合同字段更新与交车/还车生命周期更新拆开:合同保存不再修改任何交还车字段。
  3. 增加显式的当前 Scope 查询,条件必须同时包含有效车辆、有效客户、有效合同、已交车未还车、 record.customer_id = COALESCE(contract.other_customer_id, contract.customer_id)
  4. 异常关系返回隔离原因,不为其生成授权记录。
  5. 修复 listByCustomerId,但将其标注为兼容接口;车辆中台继续使用已实现的最小权限 RDS 快照同步, 不依赖一次 RPC 返回无限列表。
  6. 交车、还车聚合更新失败必须让业务事务失败或写入可重试 Outbox不能仅记录日志后继续成功。

明确不做:

  • 不把遥测位置、在线状态或总里程回写为交还车业务事实;
  • 不恢复 vehicle_info.customer_id 作为客户归属;
  • 不修改锁车、控车业务。

验收测试:

  • 客户 A 查询结果不含客户 B 车辆;空客户 ID 返回空集合;
  • 丙方客户存在时只归属 other_customer_id
  • 未交车、已还车、客户/合同不一致、缺 VIN 的车辆均不授权;
  • 合同重复保存前后,交还车单 ID、时间、里程完全不变
  • 同一车辆存在多个当前关系时整体隔离,而不是任选一条;
  • 本段验收基线已被事务事实影子查询取代;当前只读中台口径为 639 个候选、613 个可发布、26 个隔离。

回滚:

  • B1 不删除字段、不改变 Dubbo 方法签名;可按服务版本回滚;
  • 新查询与旧接口并存一个版本,车辆中台只读同步可独立停用;
  • 数据修复 SQL 与代码发布分开审批,禁止发布脚本自动改写异常关系。

B2建立客户账号一致性ln-cloud + ln-asset-management

预计修改文件/模块:

  • ln-cloud/ruoyi-common/ruoyi-common-core/.../UserType.java
  • ln-cloud/ruoyi-common/ruoyi-common-satoken/.../SaPermissionImpl.java
  • ln-cloud/ruoyi-api/ruoyi-api-system/.../RemoteUserService.java
  • ln-cloud/ruoyi-modules/ruoyi-system/.../RemoteUserServiceImpl.java
  • ln-cloud/ruoyi-modules/ruoyi-system/.../ISysUserService.java
  • ln-cloud/ruoyi-modules/ruoyi-system/.../SysUserServiceImpl.java
  • ln-cloud/ruoyi-auth 新增独立客户认证策略
  • ln-asset-management 客户账号开通、更新、停用 Outbox/补偿任务
  • 新增账号绑定/激活所需数据库迁移与测试

变更内容:

  1. 增加明确的 CUSTOMER("customer") 类型,并为客户主体返回固定、最小的门户权限,不继承后台菜单权限。
  2. 新增内部“业务账号开通”接口,不再复用公开自助注册开关;接口以 (tenantId, userType, businessId) 幂等,并校验用户名、手机号冲突。
  3. 增加显式业务绑定,不能仅依赖 sys_user.user_id == customer_info.id 的偶然约定。
  4. 客户档案事务写入 Outbox账号、角色、绑定创建失败可重试、可告警、可人工补偿。前端明确展示“账号待开通” 不再静默成功。
  5. 删除共享默认密码。采用一次性随机激活凭证,短时有效、单次使用;激活后立即失效。
  6. 新增独立 customer_password / customer_sms 登录策略。客户类型由受信客户端配置或策略固定,不能由浏览器 任意传入;后台密码登录仍只允许后台账号。
  7. 客户停用、删除或合作终止时撤销其会话,并产生身份版本变更事件。
  8. 存量补偿先输出冲突清单335 个客户不得按手机号自动合并,审计发现的 4 个手机号匹配必须人工确认。

验收测试:

  • 同用户名/手机号存在不同主体类型时,客户登录只能命中 customer
  • 客户账号不能使用后台登录策略,后台账号不能使用客户策略;
  • 公开注册关闭时,内部业务账号开通仍可按授权调用;
  • 重复 Outbox 消息不会创建重复账号、绑定或角色;
  • 激活凭证不能复用,日志中不出现明文凭证或密码;
  • 删除/停用客户后现有 token 立即失效;
  • 客户权限解析不抛 UserType not found,且没有后台菜单权限。

回滚:

  • 新客户认证使用独立 grant type 和独立客户端,关闭该客户端即可停止入口;
  • 绑定表和 Outbox 只新增,不破坏现有后台账号;
  • 回滚应用版本前先停止补偿消费者,不删除已经创建的客户账号,只统一停用,避免 ID 被复用。

B3向车辆中台签发短时身份ln-cloud/ruoyi-auth

推荐新增内部/登录后交换接口:

POST /inner/v1/vehicle-platform/token
Authorization: Bearer <oneos-customer-token>

服务端从 Sa-Token 会话和业务绑定取得 userId/customerId/tenantId/userType,签发最长 5 分钟、 aud=vehicle-data-platform 的短时 JWT。浏览器不能提交或覆盖 customerId

最低声明:

{
  "iss": "oneos-auth",
  "aud": "vehicle-data-platform",
  "sub": "<sys_user.user_id>",
  "subjectType": "customer",
  "customerId": "<customer_info.id>",
  "tenantId": "<tenant_id>",
  "scope": ["vehicle:read"],
  "identityVersion": 1,
  "iat": 0,
  "exp": 0,
  "jti": "<random>"
}

安全要求:

  • 使用非对称签名,车辆中台只持有公钥;密钥 ID 支持轮换;
  • 严格校验发行方、受众、算法、exp/nbf/iat、主体类型和客户 ID
  • 网关删除外部传入的同名身份头;不信任 X-Customer-Id
  • Scope 投影过期、身份绑定缺失或账号停用时,车辆中台失败关闭;
  • 任何越权详情统一返回 404避免泄露 VIN 或告警 ID 是否存在。

回滚:停止 token 交换接口或撤销对应客户端;车辆中台客户入口关闭,内部管理员入口不受影响。

4. 数据库变更必须单独审批

在修复 1 组重复聚合记录并确认软删除语义前,不直接添加唯一约束。建议顺序:

  1. 输出重复记录和 26 条隔离关系的业务核对清单;
  2. 由合同/交还车业务负责人确认每条修复方式;
  3. 在预发布库回放合同保存、交车、还车、再次交车和丙方客户用例;
  4. 再评估 vehicle_lease_order_record(vehicle_id) 唯一约束及 Scope 查询索引;
  5. DDL 使用在线方式并准备反向 DDL不与应用代码在同一步骤自动执行。

5. 推荐审批顺序

  1. B1/B2 已停止,不修改 OneOS 业务逻辑;
  2. 先完成车辆中台只读 Scope 投影与异常隔离;
  3. 客户身份入口需另行确定可信身份来源并通过双客户越权测试;
  4. 最后才进行外部客户灰度。

每个批次独立提交、独立发布、独立回滚。未经用户明确同意,不修改上述 OneOS 文件。