From 6d1d2ec634124db944011b03f23b497093b06e12 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Sat, 2 May 2026 11:29:49 +0800 Subject: [PATCH] =?UTF-8?q?docs(deploy):=20=E6=B7=BB=E5=8A=A0=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E6=96=87=E6=A1=A3=E5=B9=B6=E6=9B=B4=E6=96=B0SDK=20API?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增完整的XuqmGroup部署文档,包含服务器配置、Docker Compose部署策略 - 更新SDK API重设计规范至V2.0,统一各端SDK初始化和登录接口 - 添加安全设计规范文档,涵盖密码安全、AppSecret验证等内容 - 新增离线推送架构设计文档,定义厂商推送集成方案 - 重构SDK登录流程,统一使用userId + userSig鉴权模式 - 移除dbName等外部配置参数,实现零感知平台地址配置 - 完善部署架构图和配置示例文件 --- .../demo/controller/DemoAuthController.java | 20 ------------ .../xuqm/demo/service/DemoAuthService.java | 31 ++++--------------- docs/API_ACCESS.md | 13 ++------ .../java/com/xuqm/im/sdk/XuqmImServerSdk.java | 2 +- .../xuqm/im/controller/AuthController.java | 5 +-- .../com/xuqm/im/service/ImAccountService.java | 7 ++--- 6 files changed, 12 insertions(+), 66 deletions(-) diff --git a/demo-service/src/main/java/com/xuqm/demo/controller/DemoAuthController.java b/demo-service/src/main/java/com/xuqm/demo/controller/DemoAuthController.java index be1d5b4..433f646 100644 --- a/demo-service/src/main/java/com/xuqm/demo/controller/DemoAuthController.java +++ b/demo-service/src/main/java/com/xuqm/demo/controller/DemoAuthController.java @@ -56,31 +56,11 @@ public class DemoAuthController { private Map buildResponse(DemoAuthService.AuthResult result) { return Map.of( "demoToken", result.demoToken() != null ? result.demoToken() : "", - "demoTokenExpiresAt", result.demoTokenExpiresAt(), "imToken", result.imToken() != null ? result.imToken() : "", - "imTokenExpiresAt", result.imTokenExpiresAt(), "profile", result.profile() ); } - @PostMapping("/refresh-im") - public ApiResponse> refreshIm( - @RequestParam(required = false) String appId, - Authentication auth) { - if (auth == null || auth.getPrincipal() == null) { - return ApiResponse.unauthorized("Unauthorized"); - } - if (appId == null || appId.isBlank()) { - return ApiResponse.badRequest("appId is required"); - } - - DemoAuthService.ImCredential result = authService.refreshImToken(appId, auth.getPrincipal().toString()); - return ApiResponse.success(Map.of( - "imToken", result.token(), - "imTokenExpiresAt", result.expiresAt() - )); - } - @PostMapping("/reset-password") public ApiResponse resetPassword(@RequestBody ResetPasswordRequest body) { if (body.appId() == null || body.appId().isBlank()) { diff --git a/demo-service/src/main/java/com/xuqm/demo/service/DemoAuthService.java b/demo-service/src/main/java/com/xuqm/demo/service/DemoAuthService.java index 1068c46..5e27821 100644 --- a/demo-service/src/main/java/com/xuqm/demo/service/DemoAuthService.java +++ b/demo-service/src/main/java/com/xuqm/demo/service/DemoAuthService.java @@ -51,8 +51,8 @@ public class DemoAuthService { this.appSecretClient = appSecretClient; } - public record AuthResult(String demoToken, long demoTokenExpiresAt, String imToken, long imTokenExpiresAt, UserProfile profile) {} - public record ImCredential(String token, long expiresAt) {} + public record AuthResult(String demoToken, String imToken, UserProfile profile) {} + public record ImCredential(String token) {} public record UserProfile(String appId, String userId, String nickname, String avatar, String gender) {} @@ -77,9 +77,7 @@ public class DemoAuthService { return new AuthResult( demoToken, - tokenExpiresAt(), imCredential.token(), - imCredential.expiresAt(), toProfile(user) ); } @@ -98,9 +96,7 @@ public class DemoAuthService { return new AuthResult( demoToken, - tokenExpiresAt(), imCredential.token(), - imCredential.expiresAt(), toProfile(user) ); } @@ -117,20 +113,8 @@ public class DemoAuthService { return jwtUtil.generate(userId, Map.of("appId", appId, "role", "USER")); } - private long tokenExpiresAt() { - return Instant.now().toEpochMilli() + jwtUtil.getExpirationMillis(); - } - - public ImCredential refreshImToken(String appId, String userId) { - DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId) - .orElseThrow(() -> new BusinessException(404, "User not found: " + userId)); - return callImServiceLogin(appId, userId); - } - /** * Calls im-service to ensure the IM account exists and obtain an IM token. - * POST {imServiceUrl}/api/im/auth/login?appId={appId}&userId={userId} - * Response: {"code":200,"data":{"token":"..."}} */ private ImCredential callImServiceLogin(String appId, String userId) { long timestamp = System.currentTimeMillis(); @@ -163,18 +147,15 @@ public class DemoAuthService { JsonNode data = body.path("data"); String token = data.path("token").asText(null); if (token == null || token.isBlank()) { - throw new BusinessException(502, "Failed to refresh IM token"); + throw new BusinessException(502, "Failed to acquire IM token"); } - return new ImCredential( - token, - data.path("expiresAt").asLong(tokenExpiresAt()) - ); + return new ImCredential(token); } log.warn("im-service login returned unexpected response for appId={} userId={}: {}", appId, userId, body); - throw new BusinessException(502, "Failed to refresh IM token"); + throw new BusinessException(502, "Failed to acquire IM token"); } catch (RestClientException e) { log.error("Failed to call im-service login for appId={} userId={}: {}", appId, userId, e.getMessage()); - throw new BusinessException(502, "Failed to refresh IM token"); + throw new BusinessException(502, "Failed to acquire IM token"); } } diff --git a/docs/API_ACCESS.md b/docs/API_ACCESS.md index 87a9157..a50897a 100644 --- a/docs/API_ACCESS.md +++ b/docs/API_ACCESS.md @@ -143,7 +143,7 @@ | 方法 | 路径 | 鉴权 | 说明 | |------|------|------|------| | GET | `/api/v1/updates/app/check` | 否 | 检查 App 更新 | -| POST | `/api/v1/updates/app/upload` | 是 | 上传 App 版本,支持即时发布 / 定时发布 / 市场提交配置;Android 支持 `apkUrl`(来自 file-service)或旧版直传 `apkFile`,iOS / Harmony 仅记录版本号与市场跳转信息,`marketUrl` 也可以为空,不要求本地安装包;可附带 `expectedPackageName` 作为当前应用包名守卫 | +| POST | `/api/v1/updates/app/upload` | 是 | 上传 App 版本,支持即时发布 / 定时发布 / 市场提交配置;Android 通过 `apkUrl`(来自 file-service)上传安装包,iOS / Harmony 仅记录版本号与市场跳转信息,`marketUrl` 也可以为空,不要求本地安装包;可附带 `expectedPackageName` 作为当前应用包名守卫 | | POST | `/api/v1/updates/app/{id}/publish` | 是 | 发布 App 版本 | | GET | `/api/v1/updates/app/list` | 是 | App 版本列表 | | GET | `/api/v1/updates/files/apk/{filename}` | 否 | 下载 APK | @@ -240,16 +240,7 @@ curl 'https://dev.xuqinmin.com/api/v1/rn/update/check?appId=ak_demo_chat&platfor curl -X POST 'https://dev.xuqinmin.com/api/im/auth/login?appId=ak_demo_chat&userId=demo_alice' ``` -返回示例中的 `data` 会同时包含 `token` 和 `expiresAt`,用于客户端提前做静默续签。 - -### Demo IM 刷新 - -```bash -curl -X POST 'https://dev.xuqinmin.com/api/demo/auth/refresh-im?appId=ak_demo_chat' \ - -H 'Authorization: Bearer ' -``` - -该接口会基于 demo 登录态重新签发 IM token,并返回新的 `expiresAt`。 +返回示例中的 `data` 只包含 `token`。如果需要更新登录态,请由业务服务端重新调用登录接口并覆盖旧会话。 ### IM 会话与关系链 diff --git a/im-sdk/src/main/java/com/xuqm/im/sdk/XuqmImServerSdk.java b/im-sdk/src/main/java/com/xuqm/im/sdk/XuqmImServerSdk.java index 38ca922..97dad02 100644 --- a/im-sdk/src/main/java/com/xuqm/im/sdk/XuqmImServerSdk.java +++ b/im-sdk/src/main/java/com/xuqm/im/sdk/XuqmImServerSdk.java @@ -1576,7 +1576,7 @@ public final class XuqmImServerSdk { } } - public record LoginResponse(String token, long expiresAt) {} + public record LoginResponse(String token) {} public record ConversationView( String targetId, diff --git a/im-service/src/main/java/com/xuqm/im/controller/AuthController.java b/im-service/src/main/java/com/xuqm/im/controller/AuthController.java index 6cde15c..1b245c6 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/AuthController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/AuthController.java @@ -34,9 +34,6 @@ public class AuthController { } accountService.validateSignature(appId, userId, timestamp, nonce, signature); ImAccountService.LoginResult result = accountService.loginOrRegister(appId, userId); - return ResponseEntity.ok(ApiResponse.success(Map.of( - "token", result.token(), - "expiresAt", result.expiresAt() - ))); + return ResponseEntity.ok(ApiResponse.success(Map.of("token", result.token()))); } } diff --git a/im-service/src/main/java/com/xuqm/im/service/ImAccountService.java b/im-service/src/main/java/com/xuqm/im/service/ImAccountService.java index 2288733..a2f3813 100644 --- a/im-service/src/main/java/com/xuqm/im/service/ImAccountService.java +++ b/im-service/src/main/java/com/xuqm/im/service/ImAccountService.java @@ -17,7 +17,7 @@ import java.util.UUID; @Service public class ImAccountService { - public record LoginResult(String token, long expiresAt) {} + public record LoginResult(String token) {} private final ImAccountRepository accountRepository; private final JwtUtil jwtUtil; @@ -68,10 +68,7 @@ public class ImAccountService { throw new BusinessException(403, "账号已被封禁"); } - long expiresAt = jwtUtil.getExpirationMillis() > 0 - ? Instant.now().toEpochMilli() + jwtUtil.getExpirationMillis() - : Long.MAX_VALUE; - return new LoginResult(jwtUtil.generate(userId, Map.of("appId", appId, "role", "USER")), expiresAt); + return new LoginResult(jwtUtil.generate(userId, Map.of("appId", appId, "role", "USER"))); } public ImAccountEntity getAccount(String appId, String userId) {