923 lines
28 KiB
Markdown
923 lines
28 KiB
Markdown
# OneOS(RuoYi-Cloud)与车辆数据中台统一登录及业务权限集成方案
|
||
|
||
更新时间:2026-07-24
|
||
状态:首期代码已完成,待部署配置与测试环境端到端验收
|
||
责任团队:OneOS AI(Codex)、车辆数据中台 AI(Codex)
|
||
|
||
## 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 AI(Codex)开发职责
|
||
|
||
### 9.1 代码范围
|
||
|
||
允许修改:
|
||
|
||
- `ruoyi-auth`;
|
||
- `ruoyi-gateway` 路由和内部接口安全配置;
|
||
- 必需的公共 DTO、安全组件和测试;
|
||
- OneOS 前端车辆中台菜单跳转逻辑;
|
||
- SSO Ticket 专用数据库表或 Redis Key;
|
||
- SSO 运维配置和文档。
|
||
|
||
禁止修改:
|
||
|
||
- `ln_asset_management` 车辆、合同、交还车业务判断;
|
||
- 业务负责人和部门的现有权威数据语义;
|
||
- 车辆数据中台代码;
|
||
- 通过前端拼接用户信息替代服务端认证。
|
||
|
||
### 9.2 工作包 O-1:RuoYi 版本与身份字段确认
|
||
|
||
交付:
|
||
|
||
- 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-3:Ticket 创建
|
||
|
||
实现:
|
||
|
||
- 当前 RuoYi Token 验证;
|
||
- Ticket 密码学随机生成;
|
||
- Ticket 哈希存储、TTL、绑定字段;
|
||
- 单用户/IP 限流;
|
||
- 回调地址白名单;
|
||
- `no-store` 和敏感日志清理。
|
||
|
||
测试:
|
||
|
||
- 未登录、停用、无权限、错误回调、过量请求;
|
||
- Ticket 长度、唯一性和到期;
|
||
- 日志中不存在 Ticket 原文。
|
||
|
||
### 9.5 工作包 O-4:Introspection
|
||
|
||
实现:
|
||
|
||
- 服务令牌;
|
||
- HMAC-SHA256;
|
||
- 时间戳窗口;
|
||
- 请求 ID 防重放;
|
||
- 来源网络限制;
|
||
- Ticket 原子消费;
|
||
- 用户状态和权限二次校验;
|
||
- 最小身份响应。
|
||
|
||
测试:
|
||
|
||
- 错误服务令牌、签名、时间戳和请求 ID;
|
||
- Ticket 首次成功、第二次失败;
|
||
- Ticket 到期;
|
||
- 用户创建 Ticket 后被停用;
|
||
- 用户权限在创建和消费之间被移除;
|
||
- 并发消费只有一个成功。
|
||
|
||
### 9.6 工作包 O-5:可观测性和部署
|
||
|
||
实现:
|
||
|
||
- Ticket 创建/消费成功率;
|
||
- 错误码计数;
|
||
- 延迟;
|
||
- 重放和签名失败告警;
|
||
- 配置密钥轮换说明;
|
||
- 灰度开关;
|
||
- 回滚开关。
|
||
|
||
不得在指标和日志中记录 Ticket、OneOS Token 或签名密钥。
|
||
|
||
### 9.7 OneOS AI 最终交付物
|
||
|
||
- 接口实现;
|
||
- OpenAPI/接口文档;
|
||
- 字段样例和错误码;
|
||
- 自动化测试报告;
|
||
- 测试环境地址;
|
||
- 服务 Token 和签名密钥的安全交付方式;
|
||
- 回调地址白名单配置;
|
||
- 两类测试账号;
|
||
- 部署、回滚和密钥轮换说明。
|
||
|
||
## 10. 车辆数据中台 AI(Codex)开发职责
|
||
|
||
### 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-2:IdentityAdapter
|
||
|
||
实现具体 `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 AI(Codex)
|
||
|
||
```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 车辆数据中台 AI(Codex)首轮任务
|
||
|
||
```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/callback,Ticket 只在内存中使用并立即从 URL 清除;
|
||
9. 覆盖普通用户、部门负责人、停用、重放、过期、错误签名和全 API 越权测试;
|
||
10. 保留本地登录和应急 Token,SSO 异常时失败关闭。
|
||
|
||
在 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`
|