# 017 实施计划 ## 架构:最大化复用现有登录链路 ``` provider 凭证 ──▶ OAuthVerifyService.verify(provider, credential) ──▶ providerUid │ ┌───────────────────────────────────────────────────────┘ ▼ 查 info_user_oauth (provider, provider_uid) ├─ 命中 → 取 InfoUser → 校 status/del_flag → issueToken(provider) → 返回 └─ 未命中 → Redis 缓存 {provider,providerUid}(tempKey,TTL5m) → 返回 needPhone+tempKey │ ┌───────────────────────────────────────────────────────┘ ▼ (前端引导输手机号 → getcode 发短信) oauthBindPhone(tempKey, phone, code) 取 providerUid + 验短信(复用 lodeing: redis code==input || "8888") getuser(phone): ├─ 已注册 → 关联(写 oauth) └─ 未注册 → createUser(phone) 新建 → 写 oauth → issueToken(provider) → 返回 ``` - **token 签发**:复用 `JwtUtil.setToken(CacheConstants.USER_TOKEN_KEY, loginDto)`,仅给 `LoginUserDto` 加 `provider` 字段并在 setToken 写入 claim。 - **新建用户**:复用 `createUser` 的「建 InfoUser + 建钱包 + 删旧 token」逻辑;昵称=手机号不变。 - **短信**:复用 `getcode` 发送 + `lodeing` 的校验(key=phone 去+,万能码 8888)。 ## 数据模型 ```sql CREATE TABLE info_user_oauth ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL COMMENT '关联 info_user.user_id', provider VARCHAR(16) NOT NULL COMMENT 'apple/google/line', provider_uid VARCHAR(64) NOT NULL COMMENT '三方稳定用户ID(Apple sub / Google sub / LINE userId)', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_provider_uid (provider, provider_uid), KEY idx_user_id (user_id) ) COMMENT='三方账号绑定'; ``` ## API 契约 ### 1) `POST /infouser/user/oauthLogin` (`@Anonymous`) 请求 `OAuthLoginDto`: ``` provider apple|google|line credential identityToken(Apple) / idToken(Google) / accessToken(LINE) cid, cidType, deviceToken, voIPToken // 推送字段,与现有登录一致 ``` 响应(命中): ``` { code:200, msg, data: InfoUser, token } // token claim provider=本次渠道 ``` 响应(未命中,首次): ``` { code:200, msg, data:{ status:"needPhone", tempKey } } ``` ### 2) `POST /infouser/user/oauthBindPhone` (`@Anonymous`) 请求 `OAuthBindDto`: ``` tempKey, phone, code // code=短信验证码 cid, cidType, deviceToken, voIPToken ``` 响应:`{ code:200, msg, data: InfoUser, token }` ## 三家凭证校验(OAuthVerifyService) | provider | 凭证 | 校验 | 取 providerUid | 依赖 | |---|---|---|---|---| | apple | identityToken(ES256 JWT) | 拉 `appleid.apple.com/auth/keys`(JWKS) 验签 + 校 iss/aud/exp | `sub` | nimbus-jose-jwt(新增) | | google | ID-Token | GET `oauth2.googleapis.com/tokeninfo?id_token=` 取 claims + 校 aud=clientId | `sub` | httpclient4(已有) | | line | access_token | GET `api.line.me/v2/profile`(Bearer) | `userId` | httpclient4(已有) | > Google 走 tokeninfo HTTP 而非 firebase-admin,因后者需初始化 FirebaseApp+服务账号(项目未配置),tokeninfo 零配置即可。 ## 文件清单 | 类型 | 文件 | |---|---| | 新增实体 | `ruoyi-system/.../domain/InfoUserOauth.java` | | 新增 mapper | `ruoyi-system/.../mapper/InfoUserOauthMapper.java`(BaseMapper,无 XML) | | 新增校验服务 | `ruoyi-admin/.../utils/oauth/OAuthVerifyService.java` | | 新增 DTO | `ruoyi-admin/.../user/dto/OAuthLoginDto.java`、`OAuthBindDto.java` | | 改 controller | `ruoyi-admin/.../user/InfoUserController.java`(+2 方法) | | 改 token | `ruoyi-common/.../model/LoginUserDto.java`、`ruoyi-system/.../utils/JwtUtil.java` | | 改配置 | `ruoyi-admin/src/main/resources/application.yml`(oauth 段) | | 改依赖 | `ruoyi-admin/pom.xml`(+nimbus-jose-jwt) | | SQL | `updatesql/sql.md` | ## 风险 / 待验证 - Apple / Google / LINE 的凭证校验**需用各家真实 token + 正确 clientId/bundleId 联调**才能端到端验证;配置值(clientId/jwks url)由前端/运营提供后填入 application.yml。 - Apple JWKS 建议加缓存(key 偶尔轮换);初版每次拉取或加内存缓存。