feat: expand vehicle data platform capabilities

This commit is contained in:
lingniu
2026-07-27 16:46:15 +08:00
parent e3a1f80f86
commit 3c4bece72c
650 changed files with 62155 additions and 2552 deletions

View File

@@ -0,0 +1,922 @@
# OneOSRuoYi-Cloud与车辆数据中台统一登录及业务权限集成方案
更新时间2026-07-24
状态:首期代码已完成,待部署配置与测试环境端到端验收
责任团队OneOS AICodex、车辆数据中台 AICodex
## 0. 本次交付状态
截至 2026-07-24首期方案已在双边落地
- OneOS `ln-cloud``dev-ssl-codex` 分支;
- OneOS `ln-one-os-web``dev-ssl-codex` 分支;
- OneOS 已实现 Sa-Token 登录态校验、60 秒一次性 Ticket、Redis 原子核销、Service Token + HMAC + 时间戳 + Request ID 防重放;
- OneOS 已提供车辆数据中台中转页和菜单/权限初始化 SQL
- 车辆数据中台已实现 introspection 客户端、Ticket 兑换接口、外部账号即时同步、本地不透明会话和回调页;
- `vehicle:scope:department` 映射为 `department`;未具备该权限的用户映射为 `responsible`
- 中台继续在服务端按 `platform_user_business_scope` 计算 VIN不信任前端筛选。
部署时仍需完成:生成双边一致的密钥、发布 Nacos 配置、执行双边 SQL、为 OneOS 角色分配入口/部门权限,并完成两类账号验收。
## 1. 方案目标
用户已经登录 OneOS 后,从 OneOS 菜单进入车辆数据中台,应当:
1. 不再次输入用户名和密码;
2. 车辆数据中台能够确认用户身份、启停状态、部门、角色和业务负责人 ID
3. 部门级业务负责人只能查看其授权部门的车辆;
4. 普通业务人员只能查看 `responsible_user_id` 为本人的车辆;
5. 用户不能通过修改 URL、请求头、请求体或前端状态扩大车辆范围
6. OneOS 退出、停用或权限变更后,中台权限在约定时间内失效;
7. 两套系统不共享数据库账号、Redis、JWT 密钥和浏览器登录 Cookie
8. 任一鉴权、数据映射或业务范围异常均失败关闭,不回退为全量车辆。
## 2. 当前基础与缺口
### 2.1 已具备能力
车辆数据中台已经具备:
- 本地账号、菜单权限、车辆 VIN Scope 和服务端强制过滤;
- OneOS 业务车辆只读投影;
- 部门、业务负责人、客户、运营状态多选筛选;
- `platform_user.auth_provider + external_subject` 外部身份映射字段;
- `platform_user_business_scope` 业务权限配置;
- `department``responsible` 两种业务范围计算;
- `IdentityAdapter` 外部身份适配接口;
- 30 秒以内的主体缓存和失败关闭逻辑。
### 2.2 尚未具备能力
- OneOS 尚未提供正式 SSO Ticket 或 OIDC 接口;
- 车辆中台尚未注册实际的 RuoYi/OneOS `IdentityAdapter`
- 车辆中台前端尚无 OneOS 回调完成页;
- 双方尚未确认稳定角色编码、部门负责人权限编码和用户 ID 映射;
- 尚未完成双账号、跨部门和停用用户的端到端联调。
## 3. 技术决策
### 3.1 首期采用一次性 Ticket
首期采用:
> RuoYi 登录态验证 + 一次性 SSO Ticket + 服务端 introspection + 车辆中台本地会话
理由:
- 当前 OneOS 基于 RuoYi-Cloud-Plus 2.5.3 和 Sa-Token完整 `LoginUser` 保存在 Token Session/Redis
- 仅离线解析 JWT 无法可靠判断 Redis 登录态、用户停用和当前权限;
- 共享 OneOS Redis、JWT Secret 或 Cookie 会造成强耦合和较大安全风险;
- 一次性 Ticket 复用 `LoginHelper.getLoginUser()` 和当前 Sa-Token 登录态,实施范围小;
- OneOS Token 不进入车辆中台 URL、日志和存储
- 车辆中台继续使用自己的会话,现有 API 和前端改动可控。
### 3.2 后续升级路径
若 OneOS 后续建设标准 OIDC可将 Ticket/introspection 替换为:
- Authorization Code
- PKCE
- OIDC Discovery
- JWKS 非对称签名验证;
- 标准 `iss/aud/sub/iat/exp/jti` 声明。
业务权限映射、车辆 Scope 和本地会话模型保持不变。
### 3.3 明确禁止的方案
- URL 直接传递 `userId``deptId``role`
- URL 传递 OneOS Access Token
- 车辆中台读取 OneOS Redis
- 双方共享 JWT 对称签名密钥;
- 信任普通 `X-User-Id``X-Dept-Id` 等转发头;
- 通过“业务一部”“部门负责人”等显示名称判断权限;
- 前端根据角色自行过滤车辆;
- Scope 为空时解释为“不限制”。
## 4. 总体架构
```mermaid
sequenceDiagram
participant U as 用户浏览器
participant OF as OneOS 前端
participant OA as OneOS Auth/Gateway
participant VP as 车辆数据中台 API
participant VW as 车辆数据中台 Web
participant DB as 中台权限和业务投影
U->>OF: 已登录 OneOS
U->>OF: 点击车辆数据中台
OF->>OA: POST /auth/sso/vehicle-platform/tickets
Note over OF,OA: 携带当前 RuoYi Bearer Token
OA->>OA: TokenService.getLoginUser()
OA->>OA: 校验用户、部门和角色
OA-->>OF: 返回 60 秒单次 Ticket
OF->>VW: 跳转 /auth/oneos/callback?ticket=...
VW->>VP: POST /api/v2/auth/oneos/exchange
VP->>OA: POST /inner/v1/sso/vehicle-platform/introspect
Note over VP,OA: 服务身份 + HMAC + Ticket
OA->>OA: 原子消费 Ticket
OA-->>VP: 返回已验证用户声明
VP->>DB: 映射 platform_user 和业务 Scope
VP->>DB: 按部门或负责人计算 VIN
VP-->>VW: 返回中台 Access Token 和 Session
VW->>VW: 保存到 sessionStorage
VW->>U: 进入 /vehicles
```
## 5. 身份、角色与权限模型
### 5.1 OneOS 权威字段
OneOS 是以下字段的身份权威来源:
- `userId`RuoYi `sys_user.user_id`,按字符串传输;
- `username`
- `nickname`
- `status/active`
- `deptId`
- `tenantId`
- `roleKeys`
- `permissions`
- OneOS 当前登录有效期。
### 5.2 中台权威字段
车辆数据中台是以下内容的最终授权执行方:
- 中台账号是否允许登录;
- 中台菜单权限;
- OneOS 角色到中台业务范围的映射;
- 当前有效业务车辆 VIN 集合;
- 单车、列表、地图、轨迹、历史、统计和导出的服务端 Scope
- 中台会话、审计和拒绝决策。
### 5.3 推荐的 RuoYi 权限编码
OneOS 新增稳定权限编码:
```text
vehicle:platform:access
vehicle:scope:department
```
映射规则:
| OneOS 条件 | 中台 Scope | 可见车辆 |
|---|---|---|
| 用户停用 | denied | 无 |
| 无 `vehicle:platform:access` | denied | 无 |
| 有 `vehicle:scope:department` | `department` | `department_id IN departmentIds` |
| 无部门级权限且有 `userId` | `responsible` | `responsible_user_id = userId` |
| Scope 必需字段缺失 | denied | 无 |
约束:
- 不把 OneOS `admin` 自动映射为中台 `admin`
- 部门级权限以权限编码判断,不以角色显示名称判断;
- 首期 `departmentIds=[deptId]`,如需多部门必须由 OneOS 明确返回稳定 ID 数组;
- `responsible_user_id` 必须确认与 OneOS `sys_user.user_id` 使用同一 ID
- 若两者不一致,必须提供权威映射,不允许按姓名匹配。
## 6. OneOS SSO 接口契约
### 6.1 创建 Ticket
```http
POST /auth/sso/vehicle-platform/tickets
Authorization: Bearer <current-ruoyi-token>
Content-Type: application/json
```
请求:
```json
{
"audience": "vehicle-data-platform",
"redirectUri": "https://vehicle.example.com/auth/oneos/callback",
"returnTo": "/vehicles",
"requestId": "uuid"
}
```
成功响应:
```json
{
"code": 0,
"data": {
"ticket": "random-256-bit-value",
"expiresIn": 60,
"redirectUrl": "https://vehicle.example.com/auth/oneos/callback?ticket=..."
},
"requestId": "uuid"
}
```
要求:
- 只有已登录且具备 `vehicle:platform:access` 的用户可以创建;
- Ticket 至少使用 256 位密码学随机数;
- OneOS 只保存 Ticket 的 SHA-256
- 有效期建议 60 秒,最长不得超过 120 秒;
- Ticket 只能成功消费一次;
- Ticket 绑定 `audience`、用户、租户和回调地址;
- `returnTo` 仅允许车辆中台站内白名单路径;
- 对同一用户和 IP 限流;
- 响应头 `Cache-Control: no-store`
- 日志不得记录 Ticket 原文。
### 6.2 消费并解析 Ticket
```http
POST /inner/v1/sso/vehicle-platform/introspect
Authorization: Service <service-token>
X-Request-Id: <uuid>
X-Request-Timestamp: <unix-seconds>
X-Request-Signature: <hmac-sha256>
Content-Type: application/json
```
请求:
```json
{
"ticket": "random-256-bit-value",
"audience": "vehicle-data-platform"
}
```
签名原文:
```text
POST
/inner/v1/sso/vehicle-platform/introspect
<unix-seconds>
<request-id>
<sha256-lower-hex-of-body>
```
成功响应:
```json
{
"code": 0,
"data": {
"active": true,
"subject": "50001",
"userId": "50001",
"username": "zhangsan",
"nickname": "张三",
"tenantId": "000000",
"departmentIds": ["40001"],
"roleKeys": ["business_manager"],
"permissions": [
"vehicle:platform:access",
"vehicle:scope:department"
],
"identityVersion": "user-50001-v18",
"authenticatedAt": "2026-07-24T10:00:00+08:00",
"expiresAt": "2026-07-24T10:05:00+08:00"
},
"requestId": "uuid"
}
```
约束:
- 所有雪花 ID 均使用 JSON 字符串;
- introspection 必须原子消费 Ticket
- 重复消费返回统一失效错误;
- 消费时重新检查用户状态和关键权限;
- 不返回密码、手机号、身份证、RuoYi Token 和 Redis Key
- OneOS 拒绝超过 60 秒的时间戳、重复请求 ID、错误服务令牌、错误签名和错误来源网络
- 网关必须剥离外部传入的同名签名头;
- OneOS SSO 与车辆业务快照使用不同服务令牌和签名密钥。
### 6.3 错误码
| HTTP | code | 含义 |
|---|---|---|
| 400 | `SSO_REQUEST_INVALID` | 参数或回调地址无效 |
| 401 | `SSO_LOGIN_REQUIRED` | RuoYi 登录失效 |
| 403 | `SSO_ACCESS_DENIED` | 用户停用或无中台入口权限 |
| 404 | `SSO_TICKET_INVALID` | Ticket 不存在、过期或已消费 |
| 409 | `SSO_TICKET_REPLAYED` | Ticket 重放 |
| 429 | `SSO_RATE_LIMITED` | 请求过多 |
| 500 | `SSO_IDENTITY_UNAVAILABLE` | 无法读取权威用户信息 |
| 503 | `SSO_SERVICE_UNAVAILABLE` | SSO 服务不可用 |
客户端不得根据不同 Ticket 错误推测用户是否存在。
## 7. 车辆数据中台接口契约
### 7.1 Ticket 交换
```http
POST /api/v2/auth/oneos/exchange
Content-Type: application/json
```
请求:
```json
{
"ticket": "...",
"returnTo": "/vehicles"
}
```
成功响应保持与本地登录一致:
```json
{
"data": {
"accessToken": "<platform-session-token>",
"expiresAt": "2026-07-24T10:05:00+08:00",
"returnTo": "/vehicles",
"session": {
"subjectId": "42",
"name": "张三",
"username": "zhangsan",
"role": "customer",
"userType": "customer",
"authProvider": "OneOS",
"menuKeys": ["vehicles"],
"vehicleCount": 18,
"businessScopeLevel": "department",
"departmentIds": ["40001"]
}
}
}
```
### 7.2 中台交换处理
1. 校验请求体大小、Ticket 格式和站内 `returnTo`
2. 使用独立服务身份调用 OneOS introspection
3. 校验 `active``subject``expiresAt`、访问权限和必需 Scope 字段;
4.`(auth_provider='OneOS', external_subject=subject)` 查找账号;
5. 按策略自动创建或更新中台客户账号;
6. 在同一数据库事务更新:
- `platform_user`
- `platform_user_menu`
- `platform_user_business_scope`
- 身份同步审计;
7. 读取当前 OneOS 业务投影并计算 VIN
8. Scope 计算异常时不创建会话;
9. 创建中台随机会话 Token数据库只保存 SHA-256
10. 返回中台 Session不返回 OneOS Ticket 或 OneOS Token。
### 7.3 会话策略
- OneOS 中台会话首期建议最长 5 分钟;
- 前端可在会话即将到期时重新走静默 Ticket 流程;
- 中台主体缓存最长 30 秒;
- OneOS 身份版本变化后,新 exchange 立即生效;
- OneOS 用户停用最迟在当前 5 分钟会话结束时生效;
- 如要求近实时停用,可增加 OneOS 会话撤销通知或每 30 秒 introspection
- 退出中台只撤销中台会话,不必退出 OneOS
- OneOS 全局退出后不得继续签发新 Ticket。
## 8. 数据映射与数据库计划
### 8.1 复用表
```text
platform_user
platform_user_menu
platform_user_session
platform_user_business_scope
business_scope_state
business_customer_vehicle_scope
platform_auth_audit
```
### 8.2 建议新增身份同步审计表
```text
platform_external_identity_sync_audit
id
auth_provider
external_subject
identity_version
scope_level
department_ids
responsible_user_id
result
reason_code
trace_id
created_at
```
安全要求:
- 不保存 Ticket、OneOS Token、服务密钥
- 审计中的用户 ID 可保存VIN 只在必要时保存摘要;
- `department_ids` 标准化、去重和限长;
- 账号和业务 Scope 更新必须事务化;
- OneOS 已映射账号不存在时,默认策略必须明确选择:
- 推荐:允许受控 JIT 自动创建 `customer`
- 更严格:管理员预先创建,未知身份拒绝。
## 9. OneOS AICodex开发职责
### 9.1 代码范围
允许修改:
- `ruoyi-auth`
- `ruoyi-gateway` 路由和内部接口安全配置;
- 必需的公共 DTO、安全组件和测试
- OneOS 前端车辆中台菜单跳转逻辑;
- SSO Ticket 专用数据库表或 Redis Key
- SSO 运维配置和文档。
禁止修改:
- `ln_asset_management` 车辆、合同、交还车业务判断;
- 业务负责人和部门的现有权威数据语义;
- 车辆数据中台代码;
- 通过前端拼接用户信息替代服务端认证。
### 9.2 工作包 O-1RuoYi 版本与身份字段确认
交付:
- RuoYi 分支、Spring Boot 版本和认证组件说明;
- 当前 Token Header、前缀和失效机制
- `LoginUser` 可稳定取得的字段;
- `userId → responsible_user_id` 一致性结论;
- 部门负责人角色/权限编码;
- 测试账号清单。
完成标准:
- 不依赖姓名匹配;
- 明确单部门或多部门;
- 明确停用用户的判定字段。
### 9.3 工作包 O-2权限编码与菜单入口
实现:
- 新增或确认 `vehicle:platform:access`
- 新增或确认 `vehicle:scope:department`
- 配置部门负责人和普通业务人员;
- OneOS 菜单只对具备入口权限的用户显示;
- 菜单点击前调用创建 Ticket 接口。
测试:
- 无权限用户不可见且接口返回 403
- 普通业务人员不会获得部门级权限;
- OneOS 管理员不会自动获得中台管理员权限。
### 9.4 工作包 O-3Ticket 创建
实现:
- 当前 RuoYi Token 验证;
- Ticket 密码学随机生成;
- Ticket 哈希存储、TTL、绑定字段
- 单用户/IP 限流;
- 回调地址白名单;
- `no-store` 和敏感日志清理。
测试:
- 未登录、停用、无权限、错误回调、过量请求;
- Ticket 长度、唯一性和到期;
- 日志中不存在 Ticket 原文。
### 9.5 工作包 O-4Introspection
实现:
- 服务令牌;
- HMAC-SHA256
- 时间戳窗口;
- 请求 ID 防重放;
- 来源网络限制;
- Ticket 原子消费;
- 用户状态和权限二次校验;
- 最小身份响应。
测试:
- 错误服务令牌、签名、时间戳和请求 ID
- Ticket 首次成功、第二次失败;
- Ticket 到期;
- 用户创建 Ticket 后被停用;
- 用户权限在创建和消费之间被移除;
- 并发消费只有一个成功。
### 9.6 工作包 O-5可观测性和部署
实现:
- Ticket 创建/消费成功率;
- 错误码计数;
- 延迟;
- 重放和签名失败告警;
- 配置密钥轮换说明;
- 灰度开关;
- 回滚开关。
不得在指标和日志中记录 Ticket、OneOS Token 或签名密钥。
### 9.7 OneOS AI 最终交付物
- 接口实现;
- OpenAPI/接口文档;
- 字段样例和错误码;
- 自动化测试报告;
- 测试环境地址;
- 服务 Token 和签名密钥的安全交付方式;
- 回调地址白名单配置;
- 两类测试账号;
- 部署、回滚和密钥轮换说明。
## 10. 车辆数据中台 AICodex开发职责
### 10.1 代码范围
允许修改:
- `apps/api/internal/app` 鉴权和会话;
- `apps/api/internal/config` SSO 配置;
- `apps/api/internal/platform` Principal 和业务 Scope
- `apps/web/src/v2/auth` 回调和会话恢复;
- 中台数据库迁移;
- 中台部署配置、测试和文档。
禁止修改:
- OneOS/RuoYi 源码;
- OneOS Redis 和业务数据库;
- OneOS 角色或部门事实;
- 通过直接查询 `ln_asset_management` 判断用户登录态。
### 10.2 工作包 V-1配置和 OneOS 客户端
新增配置:
```text
ONEOS_SSO_ENABLED=false
ONEOS_SSO_INTROSPECTION_URL=
ONEOS_SSO_SERVICE_TOKEN=
ONEOS_SSO_SIGNING_SECRET=
ONEOS_SSO_AUDIENCE=vehicle-platform
ONEOS_SSO_DEFAULT_MENUS=vehicles
ONEOS_SSO_REQUEST_TIMEOUT_MS=3000
ONEOS_SSO_SESSION_TTL_MINUTES=30
```
实现:
- 有界 HTTP 客户端;
- 独立超时;
- 请求 ID、时间戳和 HMAC
- 结构化错误;
- 429/5xx 有界重试;
- 4xx 不重试;
- 响应大小限制;
- 密钥不进入日志。
### 10.3 工作包 V-2IdentityAdapter
实现具体 `OneOSIdentityAdapter`
- 调用 introspection
- 校验响应字段;
- 标准化 ID
- 校验 `active``expiresAt`
- 将 OneOS 权限映射为中台 Scope
- 禁止映射中台管理员;
- 输出统一强类型 Principal 输入。
### 10.4 工作包 V-3账号和 Scope 事务同步
实现:
- 以外部主体唯一键查询;
- JIT 创建或更新客户账号;
- 维护 `auth_provider='OneOS'`
- 更新菜单权限;
- 更新 `platform_user_business_scope`
- 记录身份版本和审计;
- 权限降级时立即清除旧 Scope
- 缺失字段失败关闭。
### 10.5 工作包 V-4交换接口和中台会话
实现:
- `POST /api/v2/auth/oneos/exchange`
- 允许该接口在未登录状态访问,但必须有严格限流;
- 创建中台随机会话;
- OneOS 会话 TTL 独立设置;
- 响应与现有本地登录保持兼容;
- 登录成功、失败和 Scope 结果进入审计;
- 交换成功后清理同一外部账号的过期会话。
### 10.6 工作包 V-5前端回调
实现路由:
```text
/auth/oneos/callback
```
行为:
- 读取 Ticket 后立即从地址栏清除;
- 调用 exchange
- 保存中台 Access Token
- 清空上一账号 React Query 缓存;
- 获取 `/api/v2/session`
- 跳转到白名单 `returnTo`
- 显示安全的加载、失败和重试界面;
- 不把 Ticket 写入本地存储、日志和错误上报;
- 保留本地账号登录作为回滚入口。
### 10.7 工作包 V-6权限回归
覆盖:
- 车辆查询和详情;
- 实时监控和地图;
- 轨迹;
- 历史数据和 RAW
- 里程统计;
- 导出;
- 告警和异步任务;
- 业务筛选候选项。
必须证明 Query、Body 和普通 Header 不能扩大 VIN Scope。
### 10.8 工作包 V-7运维与发布
实现:
- SSO 功能开关;
- SSO 成功率和延迟;
- OneOS 调用错误码;
- 登录、Scope 和拒绝审计;
- 服务密钥轮换;
- 灰度账号/部门白名单;
- 保留本地管理员和应急 Token
- 故障时关闭 SSO不开放全量车辆。
### 10.9 车辆数据中台 AI 最终交付物
- OneOS SSO 客户端和适配器;
- exchange API
- 前端回调页;
- 数据库迁移;
- 单元、集成、端到端和越权测试;
- 运维配置模板;
- 监控和审计说明;
- 发布、灰度和回滚手册。
## 11. 双方协作与交付顺序
| 阶段 | OneOS AI | 中台 AI | 退出条件 |
|---|---|---|---|
| P0 契约确认 | 字段、角色、版本确认 | Scope 和会话策略确认 | 契约冻结 |
| P1 Mock 联调 | 提供固定 introspection Mock | 完成客户端和 Adapter | 契约测试通过 |
| P2 OneOS 开发 | Ticket + introspection | exchange + 回调页 | 双方单测通过 |
| P3 测试环境 | 部署 OneOS 测试接口 | 部署中台 SSO 开关 | 两类账号可登录 |
| P4 权限验收 | 提供跨部门样本 | 全 API 越权测试 | 零越权 |
| P5 灰度 | 仅开放灰度用户 | 仅启用灰度白名单 | 运行 3 个工作日 |
| P6 正式发布 | 全量启用菜单 | 启用 SSO 入口 | 指标稳定 |
依赖关系:
1. OneOS 先交付字段和 Mock
2. 中台按冻结契约完成客户端;
3. OneOS 再交付真实接口;
4. 双方测试环境联调;
5. 完成权限验收后才能灰度;
6. 灰度期间不得关闭本地登录和应急入口。
## 12. Codex 任务交接格式
双方 Codex 每次交接必须提供:
```text
任务编号:
代码仓库与分支:
提交 SHA
接口版本:
配置变更:
数据库迁移:
测试命令与结果:
已知限制:
联调地址:
需要对方确认的字段:
回滚方式:
```
接口字段发生变化时:
1. 先更新契约;
2. 提供兼容期;
3. 双方契约测试同时支持新旧版本;
4. 不允许一方静默修改字段语义;
5. 雪花 ID 类型从字符串改为数字视为破坏性变更。
## 13. 测试与验收矩阵
### 13.1 功能用例
1. OneOS 已登录用户点击菜单,无需再次输入密码;
2. 部门级负责人看到本部门全部业务车辆;
3. 普通业务人员只看到本人负责车辆;
4. 多部门负责人只看到声明的部门;
5. 四类车辆业务筛选在授权范围内正常工作;
6. 中台刷新后会话可恢复;
7. 中台退出后可重新从 OneOS 进入;
8. 本地管理员登录不受影响。
### 13.2 安全用例
1. 修改 `deptId/userId/role` Query 无效;
2. 伪造普通身份头无效;
3. Ticket 过期失败;
4. Ticket 重放失败;
5. Ticket 并发消费只有一个成功;
6. HMAC 错误失败;
7. 时间戳过期失败;
8. 请求 ID 重放失败;
9. 错误 audience 失败;
10. 用户停用失败;
11. 用户无入口权限失败;
12. 普通用户伪装部门负责人失败;
13. 客户端业务筛选不能扩大 Principal VIN Scope
14. OneOS 不可用时不回退为全量;
15. 日志、指标、前端存储中无 Ticket 和 OneOS Token。
### 13.3 数据一致性用例
1. `userId``responsible_user_id` 精确匹配;
2. 部门 ID 与业务投影 `department_id` 精确匹配;
3. 业务快照切换后新会话使用新范围;
4. 用户从部门负责人降级后不保留旧部门 Scope
5. 用户调部门后不保留旧部门车辆;
6. Scope 为空返回零车辆;
7. 业务投影不可用时拒绝业务身份登录或数据访问。
### 13.4 性能目标
- Ticket 创建 P95 小于 200 ms
- introspection P95 小于 300 ms
- 中台 exchange P95 小于 800 ms
- 登录全链路 P95 小于 2 秒;
- 单 Ticket 仅一次 OneOS introspection
- 车辆 Scope 计算不得产生按车辆 N+1 查询;
- SSO 故障不得拖垮车辆查询线程池。
## 14. 灰度、监控与告警
### 14.1 灰度顺序
1. 一个普通业务人员;
2. 一个部门级负责人;
3. 一个包含多客户和多运营状态的部门;
4. 10% 业务用户;
5. 全量业务用户。
### 14.2 核心指标
- Ticket 创建数、成功率、拒绝率;
- introspection 成功率、重放数、签名失败数;
- exchange 成功率和阶段耗时;
- JIT 创建/更新账号数;
- department/responsible Scope 用户数;
- 零车辆会话数;
- 权限拒绝数;
- OneOS 调用超时和 5xx
- 会话失效和重新登录次数。
### 14.3 告警
- 5 分钟内 SSO 成功率低于 95%
- 签名失败或重放出现;
- 零车辆会话数量突增;
- department Scope 车辆数量异常增长;
- OneOS 用户停用但中台仍成功创建会话;
- 业务投影超过允许陈旧时间;
- 同一外部主体映射多个中台账号。
## 15. 发布与回滚
### 15.1 发布前
- 契约冻结;
- 双方自动化测试通过;
- 密钥通过安全渠道配置;
- 回调域名和内网白名单完成;
- 数据库迁移完成;
- 本地管理员和应急 Token 验证;
- 灰度开关默认关闭;
- 监控和告警已部署。
### 15.2 回滚
OneOS 回滚:
- 隐藏车辆中台菜单;
- 关闭 Ticket 签发;
- 保留接口日志和指标;
- 不影响 OneOS 原有登录。
中台回滚:
- `ONEOS_SSO_ENABLED=false`
- 停止接受新的 OneOS exchange
- 撤销现有 OneOS 中台会话;
- 保留本地账号和应急 Token
- 不删除身份映射和审计;
- 绝不把 OneOS 用户降级为无 Scope 全量账号。
## 16. 评审前待确认项
OneOS 团队必须回答:
1. 是标准 RuoYi-Cloud、RuoYi-Cloud-Plus 还是二次认证实现?
2. 当前分支、Spring Boot 版本和 TokenService 实现位置?
3. `userId` 是否等于业务投影 `responsible_user_id`
4. 用户是否只有一个 `deptId`
5. 哪个稳定权限编码代表部门全部车辆权限?
6. 是否接受增加两个 `/inner/v1/sso` 接口?
7. Ticket 存 Redis 还是专用数据库表?
8. OneOS 测试环境、网关地址和网络白名单是什么?
9. 是否存在统一登出或账号停用通知需求?
10. 生产回调域名是什么?
车辆中台团队必须回答:
1. JIT 自动创建还是管理员预创建?
2. OneOS 用户默认开放哪些中台菜单?
3. 5 分钟会话 TTL 是否满足停用时效?
4. 是否需要多部门 Scope
5. 业务投影最大允许陈旧时间是多少?
6. 灰度用户和部门名单是什么?
## 17. 双方 Codex 首轮任务指令
### 17.1 发给 OneOS AICodex
```text
请在 OneOS RuoYi-Cloud 仓库中先完成只读调研,不修改 ln_asset_management 业务逻辑。
目标:
1. 确认 RuoYi 分支、Spring Boot 版本、TokenController、TokenService、LoginUser 和 Gateway 鉴权链路;
2. 确认 sys_user.user_id、dept_id、角色 key、权限字符串、用户状态字段
3. 核对 sys_user.user_id 是否与车辆业务关系 responsible_user_id 一致;
4. 设计并实现:
POST /auth/sso/vehicle-platform/tickets
POST /inner/v1/sso/vehicle-platform/introspect
5. 使用当前 RuoYi 登录态创建 60 秒单次 Ticket
6. introspection 使用独立 Service Token、HMAC、时间戳和 Request ID 防重放;
7. 返回最小身份字段,不返回 OneOS Token、密码、手机号和 Redis Key
8. 增加并发单次消费、过期、停用、权限移除、签名和重放测试;
9. 提供接口契约、测试命令、配置项、回滚方式和提交 SHA。
禁止:
- URL 传 OneOS Token
- 共享 Redis/JWT Secret
- 信任浏览器 userId/deptId/role
- 修改车辆、合同、交还车业务逻辑。
```
### 17.2 车辆数据中台 AICodex首轮任务
```text
在车辆数据中台实现 OneOS RuoYi-Cloud SSO 接入。
目标:
1. 新增 OneOS SSO 配置和有界 introspection 客户端;
2. 实现 OneOSIdentityAdapter
3. 新增 POST /api/v2/auth/oneos/exchange
4. 以 (OneOS, subject) 映射 platform_user
5. 按 vehicle:scope:department 映射 department Scope否则映射 responsible Scope
6. 事务更新账号、菜单、platform_user_business_scope 和审计;
7. 创建最长 5 分钟的中台会话;
8. 新增 /auth/oneos/callbackTicket 只在内存中使用并立即从 URL 清除;
9. 覆盖普通用户、部门负责人、停用、重放、过期、错误签名和全 API 越权测试;
10. 保留本地登录和应急 TokenSSO 异常时失败关闭。
在 OneOS 正式接口未交付前,先使用契约 Mock 开发,不伪造生产用户信息。
```
## 18. 参考
- RuoYi-Cloud 官方认证中心说明:<https://doc.ruoyi.vip/ruoyi-cloud/cloud/auth.html>
- RuoYi-Cloud 官方 `TokenController`<https://gitee.com/y_project/RuoYi-Cloud/blob/springboot3/ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java>
- RuoYi-Cloud 官方 `TokenService`<https://gitee.com/y_project/RuoYi-Cloud/blob/master/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java>
- 中台业务范围契约:`docs/oneos-customer-vehicle-scope-contract.md`
- 中台鉴权说明:`docs/authentication-authorization.md`
- 中台 OneOS 用户 Scope 迁移:`deploy/migrations/039_oneos_business_user_scope.sql`