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...

7.6 KiB

数字人民币系统:单后端 SSO 与只读用户设计

1. 目标与边界

数字人民币系统在现有 digital-rmb-backend 中同时实现两个登录入口:

  • 主平台跳转后的单点登录;
  • 用户直接访问系统后的学校 CAS 统一认证登录。

主平台不做改造。用户、教师/学生身份及角色均以主平台为唯一来源;数字人民币系统仅维护受控的只读快照,不提供用户、角色或用户角色的人工增删改接口。业务角色只有 TEACHERSTUDENT

“只读”指面向用户、管理端和公开 API 只读。内部同步任务可写入本地镜像表,否则无法完成主平台数据复制。

2. 已验证的现状

主平台使用学校 CAS 完成统一认证,在登录后签发自定义 Token它不是 OAuth2/OIDC 身份提供方。

  • 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
  • 主平台用户、学生、教师表分别为 core_userstudentteacher

主平台 Token 的 HMAC 密钥由教师或学生记录的 addTime 派生,不能使用 PEVC 示例中的固定共享密钥方式验签。PEVC 示例采用的也是“父系统 JWT + 自定义共享密钥”协议,并非 OAuth2。

3. 总体架构

不新增独立部署的认证服务。认证、防腐适配和本系统 JWT 都在现有 Spring Boot 后端内实现。

主平台 ──携带自定义 Token 跳转──> digital-rmb-backend ──签发本系统 JWT──> 前端
学校 CAS ──CAS Ticket 认证────────> digital-rmb-backend ──签发本系统 JWT──> 前端
digital-rmb-backend ──SELECT only──────────────────────────> 主平台数据库

主平台 Token 适配与 CAS 协议放入 platform-integration 防腐层。identity 限定上下文维护只读快照与角色投影;security 限定上下文签发、校验和撤销数字人民币系统自己的 JWT。业务域只依赖 CurrentActor(主平台用户 ID、教师/学生角色、状态),不依赖 CAS 或主平台 Token 细节。

4. 登录流程

4.1 主平台单点登录

  1. 主平台既有跳转链接访问 GET /api/v1/auth/sso?token=...
  2. 后端按 Token 中未验签的用户 ID 和身份类型定位主平台候选记录;
  3. 后端读取候选教师或学生记录的 addTime,按主平台算法完成 HMAC 验签;
  4. 后端读取主平台用户状态、教师/学生资料及角色,刷新本地只读快照;
  5. 后端生成仅一次、短时有效的登录兑换码,重定向到配置的前端回调地址;
  6. 前端调用 POST /api/v1/auth/session/exchange 兑换本系统 JWT 与刷新令牌。

4.2 直接访问的独立登录

  1. 用户访问 GET /api/v1/auth/cas/login
  2. 后端将浏览器重定向至学校 CAS 登录页,并使用固定的回调地址作为 CAS service
  3. CAS 将 ticket 回调至 GET /api/v1/auth/cas/callback
  4. 后端调用学校 CAS 的 serviceValidate 接口验证 Ticket取得学校账号
  5. 后端以学校账号查询主平台 core_user,仅接受教师或学生,再刷新快照;
  6. 后端创建登录兑换码,前端兑换本系统 JWT 与刷新令牌。

用户已在学校 CAS 或主平台登录时,第 2 步无感完成;没有 CAS 会话时,用户在学校认证页输入统一账号密码。本系统不维护第二套用户名和密码。

4.3 退出

POST /api/v1/auth/logout 只撤销本系统刷新令牌与本地会话;默认不退出学校 CAS 或主平台,避免跨系统连带登出。

5. 本地只读投影

用途 写入者
platform_user_snapshot 主平台用户 ID、账号、姓名、状态、同步时间 内部同步任务
role 固定角色 TEACHERSTUDENT 数据库迁移
user_role 主平台用户到教师/学生角色的镜像 内部同步任务
platform_identity_link 主平台用户 ID 与本系统主体的稳定映射 内部同步任务
auth_refresh_token 本系统可撤销刷新令牌摘要 认证模块
login_exchange_code 一次性前端兑换码摘要及过期时间 认证模块

角色映射以主平台 core_user.job_type1 为准:JT_S_02 映射为 TEACHERJT_S_03 映射为 STUDENT。其他身份、已删除用户、禁用教师或禁用学生均拒绝登录。

主平台用户 ID 是稳定关联键,不按姓名、手机号或可变用户名合并用户。同步采用首次全量、定时增量和每次成功登录即时刷新;本系统的用户与角色接口均为只读。

6. 安全规则

6.1 主平台 Token

  1. 限制 Token 长度、字符集和主平台约定的 JWT 加登录时间戳结构;
  2. 未验签声明只用于查询候选记录;
  3. 严格使用候选学生或教师记录的 addTime 重建 HMAC 密钥并验证签名;
  4. 比较 Token 身份类型、主平台 job_type1 和目标资料表的一致性;
  5. 检查状态,并对 Token 的 SHA-256 指纹作一次性消费;跳转 Token 最长有效窗口为 120 秒;
  6. 验签后绝不透传主平台 Token业务接口只接受本系统 JWT。

6.2 URL 与前端回调

跳转 Token 仅由 SSO 入口接收,之后立即重定向到不含 Token 的 URL。相关响应设置 Cache-Control: no-storeReferrer-Policy: no-referrer;反向代理、访问日志和异常日志必须脱敏 token 参数。

前端回调地址只能来自白名单配置,禁止请求参数指定任意重定向地址。回调中只携带一次性兑换码,不能携带主平台 Token 或本系统 JWT。

6.3 CAS

CAS service 地址必须固定并使用 HTTPS。Ticket 仅能向配置的 CAS serviceValidate 地址验证XML 解析必须关闭外部实体和 DTD防止 XXE。CAS 返回的账号只是身份索引,仍必须通过主平台只读数据确认教师/学生角色和状态。

6.4 数据库权限

后端使用独立的主平台只读账号,仅对 core_userstudentteacher 及必要关联表授予 SELECT。禁止授予 INSERTUPDATEDELETECREATEALTER 或 DDL 权限。

现有脚手架的本地引导管理员密码入口仅保留给开发期;生产环境禁用。教师和学生均走主平台 Token 或 CAS 登录。

7. 对外接口

  • GET /api/v1/auth/sso?token=...:主平台单点登录入口;
  • GET /api/v1/auth/cas/login:发起学校 CAS 认证;
  • GET /api/v1/auth/cas/callback?ticket=...:固定 CAS 回调;
  • POST /api/v1/auth/session/exchange:以一次性兑换码换取本系统 JWT
  • GET /api/v1/auth/me:读取当前用户与教师/学生角色;
  • POST /api/v1/auth/logout:撤销本系统会话。

Swagger 只公开上述认证和当前用户读取接口;不公开用户、角色、用户角色 CRUD。

8. 验收与测试

  • 有效主平台教师 Token 返回 TEACHER,学生 Token 返回 STUDENT
  • 伪造、篡改、过期、重放、身份不匹配或状态异常的 Token 均被拒绝;
  • CAS 有会话和无会话两种直接登录路径均可完成;
  • CAS Ticket 验证失败、CAS 返回非教师/学生、主平台查询失败均返回受控错误;
  • 登录兑换码一次性、短时有效,不能被重放;
  • 主平台数据库账号仅能 SELECT任何写操作都失败
  • 用户、角色和用户角色的写接口不存在或被拒绝;
  • Swagger 不展示用户/角色 CRUD且不会记录 Token。