You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digital-rmb-backend/docs/superpowers/specs/2026-08-03-platform-sso-rea...

144 lines
7.7 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 数字人民币系统:主平台单点登录与只读用户设计
## 1. 目标与边界
数字人民币系统需要同时支持:
- 从天泽主平台跳转后的无感单点登录;
- 用户直接访问数字人民币系统后,通过学校 CAS 统一认证登录;
- 仅教师和学生两种业务角色。
主平台不做任何改造。用户、教师/学生身份与角色的唯一主数据源为主平台;数字人民币系统不提供用户、角色或用户角色的人工增删改接口。
“只读”是指面向用户和管理端只读。为满足角色复制要求,系统内部的受控同步任务会维护本地镜像表,不接受外部写入。
## 2. 已验证的现状
主平台不是 OAuth2/OIDC 身份提供方:它使用学校 CAS 作为单点登录源,并在登录后签发自定义 Token。
- CAS 配置位于主平台 `web/src/main/resources/application.properties`
- CAS Filter 配置位于 `web/src/main/java/cn/jlw/Interceptor/CasConfig.java`
- 自定义 Token 的生成和 HMAC 验证算法位于 `web/src/main/java/cn/jlw/token/TokenService.java`
- CAS 用户到教师/学生的映射位于 `web/src/main/java/com/ibeetl/jlw/service/CasUserLoginService.java`
该 Token 的 HMAC 密钥由相应主平台教师/学生记录的 `addTime` 派生。因此,数字人民币系统不能只解析 Token 后信任其中声明;验签必须结合主平台只读数据完成。
## 3. 总体架构
新增独立的认证桥接服务Authentication Bridge
1. 对数字人民币系统提供 OAuth2/OIDC 授权码模式;
2. 对学校 CAS 作为 CAS Client
3. 接收并验证主平台跳转时携带的自定义 Token
4. 使用主平台只读数据同步用户身份和教师/学生角色;
5. 使用 RS256 签发 OIDC 令牌,发布 OpenID Provider Configuration 与 JWKS。
数字人民币后端作为 OAuth2/OIDC Client完成 OIDC 回调后签发自己的短期 API JWT。所有业务接口只认可本系统 JWT不接受主平台 Token。
```
主平台 ──主平台 Token 跳转──> 认证桥接服务 ──授权码回调──> 数字人民币系统
学校 CAS ──CAS 身份认证──────> 认证桥接服务
数字人民币系统 ──只读用户/角色快照──> 本地 MySQL
认证桥接服务 ──SELECT only────────> 主平台数据库
```
## 4. 登录流程
### 4.1 从主平台跳转
1. 主平台通过既有跳转链接将 `token` 传给桥接服务的 `GET /bridge/sso/platform?token=...`
2. 桥接服务验证 Token加载主平台教师/学生身份及状态;
3. 桥接服务完成或刷新本地快照,并创建仅一次的 OAuth2 授权码;
4. 浏览器被重定向到数字人民币系统的固定 OIDC 回调地址;
5. 数字人民币后端以授权码换取并验证 OIDC Token签发自身访问 JWT 与刷新令牌。
### 4.2 用户直接访问
1. 数字人民币系统的 `GET /api/v1/auth/sso/login` 发起桥接服务 OAuth2 授权码流程;
2. 桥接服务跳转学校 CAS已登录 CAS 的用户无感通过,未登录用户在学校认证页登录;
3. CAS 回调桥接服务后,桥接服务从主平台只读数据识别教师或学生;
4. 后续流程与 4.1 的第 3 至 5 步相同。
这就是独立登录:直接进入数字人民币系统并使用学校统一账号认证,而不是维护第二套用户名和密码。
### 4.3 退出
数字人民币系统退出只撤销自身刷新令牌和本地会话;默认不退出学校 CAS 或主平台,避免跨系统连带登出。
## 5. 身份、角色与只读快照
本地表是主平台的投影,不是主数据:
| 表 | 用途 | 写入者 |
| --- | --- | --- |
| `platform_user_snapshot` | 主平台用户 ID、账号、姓名、状态、同步时间 | 同步任务 |
| `role` | 固定角色 `TEACHER`、`STUDENT` | 数据库迁移 |
| `user_role` | 主平台用户到教师/学生角色的镜像 | 同步任务 |
| `platform_identity_link` | 主平台用户 ID 与本系统内部主体的稳定映射 | 同步任务 |
| `auth_refresh_token` | 本系统可撤销刷新令牌摘要 | 认证模块 |
角色映射以主平台 `jobType1` 为准:`JT_S_02` 映射为 `TEACHER``JT_S_03` 映射为 `STUDENT`。其他身份不允许进入本系统。每次成功登录均即时刷新;同时执行首次全量和定时增量同步。
不按姓名、手机号或可变用户名自动合并用户。主平台用户 ID 是跨同步、角色和身份关联的稳定键。
## 6. Token 验证与安全规则
桥接服务的主平台 Token 适配器按以下顺序处理:
1. 限制 Token 长度、字符集及主平台约定的 JWT 加登录时间戳结构;
2. 将未验签的用户 ID 和身份类型仅用于定位候选主平台记录;
3. 读取候选教师或学生记录的 `addTime`,按主平台算法重建 HMAC 密钥并验证签名;
4. 校验用户状态、身份类型和角色映射;
5. 以 Token 的 SHA-256 指纹进行一次性消费,跳转 Token 最长有效期为 120 秒;
6. 验签成功后不透传 Token而是进入 OAuth2/OIDC 授权码流程。
Token 出现在 URL 的风险通过以下措施降低:
- 该参数仅由桥接入口接收,成功或失败后立即重定向到不含 Token 的 URL
- 所有相关响应设置 `Cache-Control: no-store``Referrer-Policy: no-referrer`
- 反向代理、应用访问日志和异常日志必须对 `token` 参数脱敏;
- 仅允许 HTTPS、固定回调地址、`state`、`nonce` 与 PKCE
- 授权码为一次性且短时有效。
桥接服务与数字人民币系统间使用 RS256数字人民币系统通过 JWKS 验签并校验 `iss`、`aud`、`exp`、`nonce`。不得共享 HMAC 密钥。
## 7. 数据库权限与运行限制
桥接服务使用独立的主平台数据库只读账号,仅授予所需用户、教师、学生及身份关联表的 `SELECT` 权限。严禁授予 `INSERT`、`UPDATE`、`DELETE`、`CREATE`、`ALTER` 或 DDL 权限。
数字人民币系统不得通过接口修改 `platform_user_snapshot`、`role`、`user_role` 或 `platform_identity_link`。现有脚手架中的本地引导管理员登录仅限开发期;实现本设计后,生产环境将禁用该本地密码入口,教师和学生均走统一认证。
## 8. DDD 边界
- `identity` 限定上下文:只读用户快照、身份链接、教师/学生角色投影;
- `security` 限定上下文:本系统 JWT、刷新令牌、授权回调与当前用户
- `platform-integration` 防腐层:主平台 Token 验签、只读查询、CAS/OIDC 桥接;
- 业务域只依赖 `CurrentActor`(主平台用户 ID、角色、状态不依赖 CAS、OIDC 或主平台 Token 细节。
## 9. 接口边界
保留或新增的公开认证入口:
- `GET /api/v1/auth/sso/login`:发起直接统一认证;
- `GET /login/oauth2/code/platform-bridge`:固定 OIDC 回调;
- `GET /api/v1/auth/me`:读取当前用户与角色;
- `POST /api/v1/auth/logout`:撤销本系统会话。
桥接服务专用入口:
- `GET /bridge/sso/platform?token=...`:主平台跳转入口;
- 标准 OIDC discovery、authorize、token 与 JWKS 端点。
不提供用户、角色、用户角色的 CRUD API。
## 10. 验收与测试
- 主平台教师 Token 映射 `TEACHER`,学生 Token 映射 `STUDENT`
- 伪造、篡改、过期、重放或身份不匹配的 Token 均被拒绝;
- 被禁用用户和非教师/学生身份均被拒绝;
- CAS 有会话与无会话两种直接登录流程均可完成;
- OAuth2 `state`、`nonce`、PKCE、回调地址和 JWKS 验签均有集成测试;
- 数据库账号只能 SELECT尝试任何写操作均失败
- 用户、角色和用户角色写接口不存在或返回拒绝结果;
- Swagger 中不展示用户/角色 CRUD认证入口与错误码有文档。