# 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:83` 的 `listByCustomerId` 忽略 `customerId`,实际只按 `del_flag=0` 查询。其 VO 转换也没有回填 `customerId` 和 `contractCode`。 该接口在修复前必须保持内部禁用,不能作为车辆数据中台的授权来源。 ### 2.2 当前租赁 Mapper 会丢字段 `ln-asset-management/src/main/resources/mapper/VehicleLeaseOrderRecordMapper.xml:6` 的 `BaseResultMap` 与 `Base_Column_List` 缺少以下实体字段: - `customer_id`、`project_name`; - `delivery_vehicle_id`、`last_delivery_name`; - `return_vehicle_task_id`、`last_return_name`; - `update_by`。 使用这些自定义查询取得记录后,上述字段会变成空值。生产审计同时发现聚合记录与最新历史记录有 325 条关键字段差异,不能把空值当成“无业务关系”。 ### 2.3 合同保存会清空交还车事实 `VehicleLeaseOrderRecordServiceImpl.java:262` 在 `deliveryVehicleId == null` 时,同时清空交车和还车的 单据 ID、时间、里程与操作人。合同提交/更新并不代表交车事实撤销,因此这里违反业务事实的单一写入原则。 交车字段只能由交车完成/撤销流程修改;还车字段只能由还车完成/撤销流程修改。合同更新只能更新客户、合同、 项目和业务组织字段。 ### 2.4 客户账号当前不能安全登录 - `CustomerInfoServiceImpl.java:188` 先尝试创建 `sys_user`,之后才保存客户档案;远程调用失败被吞掉,两个库之间不存在事务一致性。 - `SysUserRegistrar.java:27` 给所有业务账号使用共享初始密码 `ln123456`。 - `RemoteUserServiceImpl.java:222` 把业务账号开通绑定到公开注册开关 `sys.account.registerUser`。 - `UserType.java:14` 只支持 `sys_user` 和 `app_user`;`customer` 会在 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`) 推荐新增内部/登录后交换接口: ```http POST /inner/v1/vehicle-platform/token Authorization: Bearer ``` 服务端从 Sa-Token 会话和业务绑定取得 `userId/customerId/tenantId/userType`,签发最长 5 分钟、 `aud=vehicle-data-platform` 的短时 JWT。浏览器不能提交或覆盖 `customerId`。 最低声明: ```json { "iss": "oneos-auth", "aud": "vehicle-data-platform", "sub": "", "subjectType": "customer", "customerId": "", "tenantId": "", "scope": ["vehicle:read"], "identityVersion": 1, "iat": 0, "exp": 0, "jti": "" } ``` 安全要求: - 使用非对称签名,车辆中台只持有公钥;密钥 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 文件。