18 KiB
OneOS 车辆业务与车辆数据中台集成分析
完整系统、模块、接口、安全、数据库和运维分析见 docs/oneos-ln-asset-management-system-analysis.md。本文件聚焦车辆数据中台集成边界。
更新时间:2026-07-14
生产数据库聚合审计结果见 oneos-production-audit-report.md。
涉及 OneOS 的精确修改文件、批次、测试和回滚边界见 oneos-change-approval-proposal.md;该提案尚未执行。
车辆数据中台全部 API 的客户 Scope、IDOR、导出和地图服务覆盖矩阵见 customer-scope-api-enforcement-matrix.md。
1. 分析范围与约束
- OneOS 根目录:
/Users/lingniu/project/ai-coding/oneos - 核心业务服务:
ln-asset-management,分支dev - 相关身份服务:
ln-cloud/ruoyi-auth、ln-cloud/ruoyi-system - 本轮仅进行只读分析,没有修改 OneOS 文件、数据库或运行配置。
- 车辆锁车、控车不在本方案范围内。
2. 系统职责边界
详细业务影响与遥测迁移边界见 oneos-business-impact-matrix.md。
OneOS 应作为权威来源
- 客户档案:
customer_info - 客户账号及启停:
ry-cloud.sys_user - 车辆基础信息:
vehicle_info、vehicle_model、vehicle_status - 合同客户:
vehicle_lease_contract_info - 当前车辆交付/归还状态:
vehicle_lease_order_record,必要时结合交还车任务表复核 - 业务筛选维度:运营状态、车型、品牌、运营公司、业务部门、合同和项目
车辆数据中台应作为权威来源
- 多协议接入状态及最后上报时间
- 实时位置、车速、SOC 和车辆告警
- 历史轨迹和原始数据证据
- 按 VIN 归并后的每日里程、统计期里程和最新总里程
- 协议数据质量与异常诊断
OneOS 当前仍通过 HASP/旧车联网接口拉取位置和总里程,其中 /vehicle-info/page?withTotalMileage=true 会按 VIN 逐车调用外部 HTTP 接口,存在 N+1 请求。新集成不应让车辆中台反向依赖这条旧链路。
3. 已确认的数据关系
权威表与用途
| 数据域 | 表 | 主键/关联 | 集成用途 | 注意事项 |
|---|---|---|---|---|
| 客户档案 | customer_info |
id |
客户名称、编码、合作状态 | 含联系人、银行等敏感字段,范围接口只取最小必要字段 |
| 客户账号 | ry-cloud.sys_user |
user_id = customer_info.id |
登录、启停、用户类型 | 账号可能缺失;当前 user_type=customer 未被权限枚举支持 |
| 账号角色 | ry-cloud.sys_user_role、sys_role |
user_id、role_id |
客户门户功能权限 | 新客户当前不自动分配角色 |
| 车辆档案 | vehicle_info |
id、vin |
VIN、车牌、车型、运营组织 | 实体已不再保存客户归属;VIN 必须核验空值和重复值 |
| 车辆状态 | vehicle_status |
vehicle_id |
运营、车辆、证照、保险状态 | online_status、里程仍混有旧链路数据,不作为中台遥测权威值 |
| 合同 | vehicle_lease_contract_info |
id、order_id |
主客户、丙方客户、合同和项目 | 有效客户为 COALESCE(other_customer_id, customer_id) |
| 当前租赁聚合 | vehicle_lease_order_record |
设计上一车一行 | 当前客户、合同、最近交还车事实 | Mapper 不完整、写入有清空风险,必须审计后使用 |
| 租赁历史 | vehicle_lease_order_record_log |
contract_id + vehicle_id |
归属和交还车复核 | 是可追溯证据之一,但当前按组合更新,并非不可变事件日志 |
| 交车事实 | delivery_vehicle |
vehicle_id、order_detail_id |
核验交车时间、里程和单据 | 完成状态枚举需与生产字典确认 |
| 还车事实 | return_vehicle_task |
vehicle_id、contract_id |
核验还车时间、里程和完成状态 | 多条完成路径会更新聚合表,部分异常不中断主流程 |
车辆数据中台不应复制 contact_mobile、身份证/信用代码、银行账号、密码等字段。客户投影只需要客户 ID、展示名称、账号状态、业务版本和同步时间。
客户与账号
新增客户时,customer_info.id 使用雪花 ID,并尝试以同一个 ID 创建 sys_user.user_id:
customer_info.id = sys_user.user_id
sys_user.user_type = customer
但账号创建失败只记录日志,不阻断客户保存,因此该关系不是天然完整的,必须进行覆盖率核验和补偿。
车辆与客户
2026-03-27 的 9a8e2a5f 提交将以下业务归属字段从 VehicleInfo 实体中移除:
customerIdcontractCodebusinessIdbusinessDeptIdcontractType
代码注释明确这些字段改由 vehicle_lease_order_record 提供。因此不能再把 vehicle_info.customer_id 当作唯一权威口径,即使旧数据库或旧文档仍保留该列。
合同存在甲方客户和丙方客户,现有业务代码的有效客户规则为:
effectiveCustomerId = other_customer_id != null ? other_customer_id : customer_id
客户车辆范围还必须考虑交还车边界:只有已经交车且尚未还车的车辆,才能视为客户当前可见车辆。仅按 vehicle_lease_order_record.customer_id 查询会把已经归还的车辆继续授权给客户。
建议的当前客户车辆口径已调整为事务事实优先:
vehicle_info.del_flag = 0
AND vehicle_lease_order_record.del_flag = 0
AND effective_customer_id = 当前客户
AND 最新有效 delivery_vehicle.delivery_status IN (2,3)
AND 不存在该交车单对应的 return_vehicle_task.status IN (2,3,5)
vehicle_lease_order_record 只用于客户归属交叉校验,不使用 last_return_time 判断生命周期,因为还车草稿会提前写入该字段。生产影子查询已验证该条件,仍需由业务抽样确认换车、合同变更、丙方客户、重复交还车和历史补录场景。
订单记录的可信度限制
vehicle_lease_order_record 的设计目标是“每辆车一条当前记录”,但当前实现还不能未经校验就作为唯一授权依据:
VehicleLeaseOrderRecordMapper.xml的BaseResultMap和Base_Column_List没有customer_id、project_name、交还车单 ID、交还车人等实体字段。调用selectByVehicleId、selectByVehicleIds等自定义查询时,这些字段会丢失。saveOrUpdateForContract()在deliveryVehicleId == null时会清空已有交车和还车字段。合同提交、重新提交、审批通过等多条路径都会调用该方法,若车辆此前已经交付,可能暂时或永久破坏当前租赁状态。- 还车提交路径先写入还车时间,完成路径又可能清空当前合同和客户字段;不同查询不能仅以
customer_id IS NOT NULL或仅以时间字段判断。 - 交还车更新失败只记录日志、不中断主流程,业务任务成功不代表聚合记录一定成功同步。
因此阶段 A 需要同时以当前聚合表、历史表、交车单、还车任务和合同表交叉核对。正式的范围快照接口应在一个受测试的查询服务中封装口径,并对异常记录失败关闭,不能让各调用方直接读取聚合表自行解释。
4. 已发现的高风险缺口
P0:现有客户车辆远程接口会返回全量车辆
RemoteVehicleService.listByCustomerId(customerId) 的客户过滤已被注释,当前实现实际查询全部未删除车辆;RemoteVehicleVo.customerId 和 contractCode 的回填也被注释。
该接口在修复前不得用于任何外部客户权限,否则存在严重跨客户数据泄露风险。
P0:客户账号体系尚不能直接用于车辆数据中台
customer_info创建成功不代表sys_user一定创建成功。- 新客户账号没有分配角色或菜单权限。
sys_user.user_type=customer,但UserType枚举只识别sys_user和app_user。- Sa-Token 权限解析会调用
UserType.getUserType(),客户账号触发权限判断时可能抛出类型不存在异常。 - 车辆数据中台当前只支持静态 Bearer Token 和
viewer/operator/admin,Principal 中没有customerId、tenantId或 VIN 范围。 - 客户账号创建复用了公开注册 RPC;该 RPC受
sys.account.registerUser开关控制。生产若关闭自助注册,客户档案仍会成功但账号创建必然失败。 - 所有业务账号使用相同初始密码
ln123456,没有发现首次登录强制改密或一次性激活机制。外部客户上线前必须废弃该做法。 - 通用密码登录按
tenantId + username查询,不按user_type区分;客户编码必须在租户内与其他类型账号全局唯一,并需要防止账号类型混淆。
推荐新增“业务账号开通”内部能力,不再复用公开注册开关:
- 以
(tenant_id, user_type, business_id)幂等开通客户账号;business_id对客户即customer_info.id。 - 同一事务或 Outbox 中完成账号、客户角色和业务绑定;失败可重试并可见,不再吞异常。
- 使用一次性激活链接或随机临时口令,首次登录强制设置密码;禁止共享默认密码。
- 登录成功后校验账号主体类型为
customer,并从服务端绑定关系取得customerId。 - 客户停用、合作终止、账号删除时撤销会话并让车辆中台短时声明快速失效。
- 存量补偿任务只处理缺失/异常账号,输出成功、冲突、跳过清单,不覆盖现有密码。
P0:OneOS 地图和车辆查询没有客户级数据隔离
MapTruckController的列表、搜索、详情和信息树均未按客户过滤。- 地图 SQL 默认返回所有符合运营状态的车辆。
VehicleInfoMapper仅声明业务部门数据权限;业务专员/主管的默认过滤逻辑当前被整体注释。- 客户账号既没有部门数据范围,也没有独立客户数据范围。
P1:代码、文档和映射存在漂移
VehicleInfo实体已移除客户和合同字段。VehicleInfoMapper.xml的基础 ResultMap 和字段清单仍包含旧字段。docs/VehicleInfo.md仍描述vehicle_info.customer_id并给出过时接口参数。- 部分详情服务明确把客户和合同字段设置为
null。 RemoteContractMatchService.matchByVehicleAtTime已处理交还车时间边界,但合同命中时直接返回contract.customerId,没有采用丙方优先的有效客户规则。VehicleLeaseOrderRecordMapper.xml未完整映射实体字段,自定义查询取得的customerId等值可能为null。- 合同保存会重置交还车字段,而交还车聚合更新异常又不会阻断主流程,存在聚合状态与真实业务任务不一致的窗口。
P0:车辆中台现有授权是“功能角色”,不是“数据范围”
当前 Principal 只有 Name 和 Role,鉴权中间件仅按 viewer/operator/admin 判断 HTTP 方法与功能权限。Store 接口和 SQL 构造器没有客户或 VIN Scope,PrincipalFromContext 也只被用于写操作的审计 Actor。
这会产生以下具体越权面:
| API 组 | 当前行为 | 客户开放前要求 |
|---|---|---|
| 监控、车辆、实时位置 | 全量查询,可按 VIN/车牌筛选 | 所有列表、汇总、点位、详情统一限定授权 VIN |
| 轨迹、历史、原始帧、里程 | 接受调用方传入 VIN/关键字 | 先校验 VIN Scope,再访问 MySQL/TDengine;空范围返回空,不返回全量 |
| 告警 | 告警列表只按业务筛选;详情直接按事件 ID 查询 | 列表和详情都通过事件 VIN 校验,越权统一返回 404 |
| 导出 | 任务没有 owner/customerId,列表展示全局任务,知道 ID 即可下载 | 任务固化创建者、客户、VIN Scope 和快照版本;列表/下载校验所有权 |
| 运维质量、接入管理、规则配置 | 只按 viewer/operator/admin 控制 | 外部客户主体默认禁止,不能因拥有 viewer 角色而开放 |
| 车辆档案写入、同步 | 管理员可写 | 仅内部管理员或受信同步服务可用,客户主体永远禁止 |
尤其是导出任务当前保存在全局 exports Map 和 jobs.json,ListHistoryExports() 不区分创建者,HistoryExportFile(id) 也不校验主体;告警详情同样存在按 ID 直接读取的问题。这两处在客户入口上线前必须按 P0 修复。
5. 推荐集成架构
身份链路
外部客户登录仍由 OneOS 管理,OneOS 负责账号启停和密码策略。车辆数据中台不复制客户密码。
推荐两种方案,优先级如下:
- OneOS Gateway 验证 Sa-Token 后,向车辆数据中台转发由共享密钥签名的身份声明,包含
userId、customerId、tenantId、role、过期时间和请求 ID。 - 车辆数据中台收到 OneOS Access Token 后,调用 OneOS 内部会话校验接口获得同样的身份声明。
禁止信任浏览器直接传入的 customerId、客户名或 VIN 列表。
车辆范围同步
OneOS 对外提供内部服务接口,返回客户当前授权车辆快照及版本:
{
"customerId": 1001,
"version": "2026-07-14T12:00:00.000Z",
"vehicles": [
{
"vehicleId": 2001,
"vin": "...",
"plateNumber": "...",
"operationStatus": "...",
"modelName": "...",
"brandName": "...",
"contractId": 3001,
"contractCode": "...",
"projectName": "...",
"scopeStartAt": "..."
}
]
}
车辆中台保存只读投影,例如:
business_customerbusiness_customer_vehicle_scopebusiness_scope_sync_runbusiness_scope_audit
所有车辆 API 在 Store/SQL 层统一追加 VIN Scope,不能逐个页面自行过滤,也不能先查询全量后在前端过滤。
推荐把范围变成显式的 QueryScope 参数,而不是只放在 context.Context 中:Store 接口若没有 Scope 参数就无法编译,从机制上减少新增查询忘记加权限的概率。MySQL 查询优先 JOIN 本地范围投影表;TDengine 单车查询先做 VIN 授权检查,多车查询使用已授权 VIN 集合并设置数量上限。空 Scope 对外部客户必须恒等于“无数据”,绝不能解释为“不限制”。
数据请求原则
- 身份声明决定客户 ID。
- 客户 ID 决定 VIN Scope。
- VIN Scope 再约束监控、车辆、轨迹、历史、里程、告警、导出和地图聚合查询。
- 内部管理员可显式选择客户;外部客户不能覆盖身份中的客户 ID。
- 当 Scope 服务不可用或同步数据过期时,外部访问应失败关闭,不得降级为全量数据。
6. 分阶段实施
阶段 A:只读数据审计
- 执行
oneos-readonly-audit.sql。 - 确认生产表结构是否仍有
vehicle_info.customer_id。 - 统计客户账号覆盖率、启用率、角色覆盖率。
- 统计当前交付车辆的 VIN 完整率、客户完整率和客户档案匹配率。
- 抽样验证丙方客户、换车、已还车和多合同场景。
验收:形成数据质量基线,业务负责人确认“当前客户车辆”的唯一口径。
阶段 B:修复 OneOS 权威接口和账号能力
该阶段已停止:用户明确要求不修改 ln-asset-management 任何逻辑。以下内容仅保留为已知风险清单,不执行。
- 修复
listByCustomerId,按有效客户和交还车边界查询。 - 增加批量客户车辆快照接口,返回 VIN 和业务版本。
- 统一有效客户规则,覆盖丙方客户。
- 修复订单记录 Mapper 字段遗漏,并禁止合同更新覆盖已经发生的交还车事实。
- 对范围异常记录给出隔离清单,不将不确定归属车辆授权给任何外部客户。
- 补充客户账号类型、角色、启停和存量账号补偿。
- 新增专用业务账号开通能力,移除共享默认密码和对公开注册开关的依赖。
- 增加双客户越权测试。
验收:客户 A、B 的车辆集合互斥;已还车辆立即退出范围;接口默认失败关闭。
阶段 C:车辆数据中台身份和 Scope 投影
- 扩展 Principal,加入主体类型、外部用户 ID、客户 ID 和租户 ID。
- 增加 OneOS 身份校验或可信代理声明校验。
- 建立客户与车辆范围投影、版本和审计表。
- 在底层查询构建器统一注入 VIN Scope。
- 覆盖监控、车辆、轨迹、历史、统计、告警、导出、地图聚合和反向地理编码相关入口。
验收:任何 URL 参数、VIN 搜索、批量接口和导出均不能越权;Scope 过期时外部请求拒绝访问。
阶段 D:客户门户和入口
- 外部子域名提供独立登录页。
- 内部 OneOS 菜单以新标签页进入车辆数据中台。
- 外部页面隐藏接入配置、运维质量和管理型功能。
- 客户页默认展示授权车辆数量、实时地图、轨迹和里程统计。
验收:内部入口统一,外部入口独立;账号停用后现有会话及时失效。
阶段 E:历史里程补录
- 定义补录文件格式和来源平台。
- 以 VIN、自然日、来源和导入批次保证幂等。
- 导入约 20 天缺失里程并输出成功、冲突、缺 VIN 和异常跳变报告。
- 不伪造无法取得的历史轨迹,页面明确轨迹数据起始时间。
验收:补录前后总量可对账,重复导入不重复累计,每条补录记录可追溯。
7. 需要修改 OneOS 前必须同步的范围
预计至少涉及以下模块,尚未进行任何修改:
ln-asset-management/ln-asset-apiln-asset-management/src/main/java/com/ln/asset/api/impl/RemoteVehicleServiceImpl.javaln-asset-management的车辆/合同 Mapper 与 Serviceln-cloud/ruoyi-common-core的用户类型定义ln-cloud/ruoyi-auth的客户登录策略ln-cloud/ruoyi-system的客户账号角色和状态管理- 可能新增 OneOS 内部 HTTP API、数据库索引和菜单脚本
修改前需要先同步:具体文件、接口契约、SQL 变更、兼容方案、回滚方案和测试范围。