docs(spec): 用 appId 作为唯一标识(来自 X-App-Id 请求头)

原方案用 platform 作为缓存 key 错误:
- 多个租户都叫 platform=wechat,缓存 key 冲突
- platform 不是真正唯一标识

按用户反馈调整:
- 凭证查询/缓存全部用 appId
- appId 来源:请求头 X-App-Id
- §3.1 加 UNIQUE KEY uk_app_id (app_id) 约束
- §5.1 流程重写:从 X-App-Id 取 appId → 缓存 key = app:creds:{appId}
- §5.2/5.3 删缓存也改用 appId
- §7.1 OAuth2 改造:从 request.getHeader("X-App-Id") 取
- 删除 §1.2 中 'client_id 映射' 的旧说法
This commit is contained in:
2026-06-07 17:08:32 +08:00
parent c576053ab6
commit 22889afedc
@@ -24,8 +24,7 @@
1.`rui-service-system` 增加 `SysApp` 实体 + CRUD + 内部接口
2. 支持多租户:每条记录区分 `owner_type=PLATFORM`(平台默认)或 `TENANT`(租户自配)
3. 凭证字段完整:覆盖社交登录 + 第三方支付 + AES 对称加密 + 证书文件
4. `OAuth2ServerConfig` 改为运行时从 `SysApp` 拉凭证,Redis 缓存 30min
5. 租户隔离按 `client_id → tenant_id` 映射
4. `OAuth2ServerConfig` 改为运行时从 `SysApp` 拉凭证,Redis 缓存 30min**用 `appId` 作为唯一标识**(来自请求头 `X-App-Id`
---
@@ -80,6 +79,7 @@ CREATE TABLE sys_app (
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_tenant_owner_platform (tenant_id, owner_type, platform, status),
UNIQUE KEY uk_app_id (app_id),
INDEX idx_tenant (tenant_id),
INDEX idx_platform (platform),
INDEX idx_status (status)
@@ -139,29 +139,28 @@ com.rui.common.oauth2.cache/
```
1. POST /oauth2/token?grant_type=wechat&code=xxx
Header: X-App-Id: wx1234567890
2. authorizationServerFilterChain 被调用
3. 从 OAuth2ClientAuthenticationToken 取 clientId
3. 从请求头 X-App-Id 取 appId
4. 查 rui_auth_oauth2_client 表 → 取 tenantId
5. AppCredentialsCache.get(platform=wechat, tenantId)
4. AppCredentialsCache.get(appId)
├─ HIT → 直接返回
└─ MISS → Feign: GET /system/inner/app/getCredentials?platform=wechat&tenantId={tenantId}
└─ MISS → Feign: GET /system/inner/app/getCredentials?appId={appId}
SysAppInnerController 查 sys_app
- 优先 owner_type=TENANT AND tenant_id={tid} AND status=1
- 缺省 owner_type=PLATFORM AND tenant_id=0 AND status=1
- 找不到 → 返回 404throw new UsernameNotFoundException 或 BizException
- WHERE app_id = {appId} AND status = 1
app_id 字段已加 UNIQUE 约束)
- 找不到 → 返回 404
把 SysApp 转 AppCredentialsVO 返回
oauth2 端写 Redis: SET app:creds:{platform}:{tenantId} = json EX 1800
oauth2 端写 Redis: SET app:creds:{appId} = json EX 1800
6. 拿到 AppCredentialsVO → 构造 WechatApiClient(appId, appSecret) 等
5. 拿到 AppCredentialsVO → 构造 WechatApiClient(appId, appSecret) 等
7. 走完登录流程,返回 token
6. 走完登录流程,返回 token
```
### 5.2 租户管理自己的 SysApp
@@ -171,10 +170,11 @@ com.rui.common.oauth2.cache/
2. POST /system/app Body: SysAppSaveDTO
- owner_type=TENANT
- platform=wechat
- app_id = "wx9999999"
- tenant_id = 当前用户 tenantId
- 业务校验:uk_tenant_owner_platform 唯一性
- 业务校验:uk_tenant_owner_platform + uk_app_id 唯一性
3. 写 DB
4. 删缓存:DEL app:creds:wechat:{tenantId}
4. 删缓存:DEL app:creds:{app_id}
5. 返回成功
```
@@ -185,22 +185,23 @@ com.rui.common.oauth2.cache/
2. POST /system/app
- owner_type=PLATFORM
- platform=wechat
- app_id = "wx1234567"
- tenant_id=0
3. 删缓存:DEL app:creds:wechat:0
4. 所有未自配的租户下次登录都会拉到这条
3. 删缓存:DEL app:creds:wx1234567
4. 所有未自配(uk_app_id 不冲突)的租户下次登录会用 appId=wx1234567 拉这条
```
---
## 6. 缓存策略
- **Key**: `app:creds:{platform}:{tenantId}`tenantId=0 表示 PLATFORM 默认
- **Key**: `app:creds:{appId}`(用 `app_id` 唯一标识,不用 platform/tenantId 因为多租户都叫 platform=wechat 会冲突
- **TTL**: 30 分钟(1800 秒)
- **失效时机**
- `SysApp` CRUD 写操作完成后
- `SysApp` 启/禁用操作后
- 超管强制刷新(可选接口)
- **防穿透**:缓存空对象 5 分钟(针对不存在的 tenantId
- **防穿透**:缓存空对象 5 分钟(针对不存在的 appId
- **序列化**:用 fastjson2 序列化 `AppCredentialsVO`
---
@@ -213,7 +214,7 @@ com.rui.common.oauth2.cache/
|---|---|
| `OAuth2ServerConfig` | 删 `@Bean @ConfigurationProperties` 声明 wechat/alipay AppProperties |
| 同上 | 注入 `SysAppFeign` + `AppCredentialsCache` |
| `authorizationServerFilterChain` | 根据 grant_type 动态选 platform,调 `appCredentialsCache.get(platform, tenantId)` 拿凭证 |
| `authorizationServerFilterChain` | `request.getHeader("X-App-Id")` 拿 appId,调 `appCredentialsCache.get(appId)` 拿凭证 |
### 7.2 兼容与过渡