From 7f7bec8d2954e8f8a9ac3a5d83f1a3585c03c6fb Mon Sep 17 00:00:00 2001 From: Leo Date: Thu, 15 Jan 2026 20:37:49 +0800 Subject: [PATCH] 1 --- doc/WPS365授权错误排查指南.md | 153 ++++++++++++++++++ .../service/impl/WPS365OAuthServiceImpl.java | 35 +++- 2 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 doc/WPS365授权错误排查指南.md diff --git a/doc/WPS365授权错误排查指南.md b/doc/WPS365授权错误排查指南.md new file mode 100644 index 0000000..d0309e0 --- /dev/null +++ b/doc/WPS365授权错误排查指南.md @@ -0,0 +1,153 @@ +# WPS365 授权错误排查指南 + +## 错误信息 + +```json +{ + "code": 40000001, + "msg": "invalid_request", + "debug": { + "desc": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. The 'redirect_uri' parameter does not match any of the OAuth 2.0 Client's pre-registered redirect urls." + } +} +``` + +## 错误含义 + +这个错误可能由以下原因导致: + +1. **缺少必需参数** - 授权请求中缺少某个必需的参数 +2. **参数值无效** - 某个参数的值格式不正确 +3. **参数重复** - 某个参数在请求中出现了多次 +4. **redirect_uri不匹配** - redirect_uri参数值与WPS365平台配置的回调地址不一致 + +## 排查步骤 + +### 1. 查看后端日志 + +查看后端日志中的授权URL和参数清单,例如: + +``` +生成授权URL: https://openapi.wps.cn/oauth2/auth?client_id=xxx&redirect_uri=... +📋 授权请求参数清单: + - client_id: AK20260114NNQJKV + - redirect_uri: https://jarvis.van333.cn/wps365-callback + - response_type: code + - scope: file.read,ksheet.read,user.info + - state: xxxxx +``` + +### 2. 检查参数名是否正确 + +**问题**:WPS365可能使用 `app_id` 而不是标准的 `client_id` + +**解决方案**: +- 如果使用 `client_id` 报错,尝试改为 `app_id` +- 查看WPS365官方文档确认正确的参数名 + +**当前代码使用**:`client_id`(标准OAuth2参数名) + +### 3. 检查必需参数是否齐全 + +授权请求必须包含以下参数: + +| 参数名 | 是否必需 | 说明 | 当前值 | +|--------|---------|------|--------| +| `client_id` 或 `app_id` | ✅ 必需 | 应用ID | 从配置读取 | +| `redirect_uri` | ✅ 必需 | 回调地址 | 从配置读取 | +| `response_type` | ✅ 必需 | 固定值 `code` | `code` | +| `scope` | ✅ 必需 | 权限范围 | `file.read,ksheet.read,user.info` | +| `state` | ⚠️ 推荐 | 防CSRF攻击 | 自动生成 | + +### 4. 检查redirect_uri是否匹配 + +这是最常见的错误原因。必须确保: + +1. **协议一致**:必须是 `https://`(不能是 `http://`) +2. **域名一致**:必须是 `jarvis.van333.cn`(不能有 `www` 前缀) +3. **路径一致**:必须是 `/wps365-callback`(不能有末尾斜杠) +4. **端口一致**:使用默认443端口,不需要写端口号 + +**在WPS365平台配置的回调地址必须与日志中的redirect_uri完全一致** + +### 5. 检查scope权限是否已申请 + +确保在WPS365开放平台已申请以下权限: +- `file.read` - 文件读取权限 +- `ksheet.read` - 在线表格读取权限 +- `user.info` - 用户信息权限 + +### 6. 尝试修改参数名 + +如果确认所有参数都正确,但仍然报错,可能是参数名问题: + +**测试方案1**:将 `client_id` 改为 `app_id` + +修改 `WPS365OAuthServiceImpl.java` 中的代码: +```java +// 原代码 +authUrl.append("?client_id=").append(appId); + +// 改为 +authUrl.append("?app_id=").append(appId); +``` + +**测试方案2**:同时提供两个参数(如果WPS365支持) +```java +authUrl.append("?app_id=").append(appId); +authUrl.append("&client_id=").append(appId); +``` + +### 7. 检查URL编码 + +确保 `redirect_uri` 参数正确进行了URL编码: +- 空格应该编码为 `%20` +- 斜杠 `/` 应该编码为 `%2F` +- 冒号 `:` 应该编码为 `%3A` + +查看日志中的"编码后"值,确认编码是否正确。 + +### 8. 验证WPS365平台配置 + +登录WPS365开放平台,检查: + +1. **应用ID(AppId)** 是否与配置文件中的 `app-id` 一致 +2. **回调地址配置** 是否与日志中的 `redirect_uri` 完全一致 +3. **权限配置** 是否已申请所需的scope权限 +4. **应用状态** 是否为"已上线"或"测试中" + +## 常见问题 + +### Q1: 参数名应该用 `client_id` 还是 `app_id`? + +**A**: 根据WPS365官方文档确认。标准OAuth2使用 `client_id`,但某些平台可能使用 `app_id`。如果 `client_id` 不工作,尝试 `app_id`。 + +### Q2: 为什么redirect_uri明明配置了还是报错? + +**A**: 最常见的原因是: +- 平台配置的回调地址与代码中的不完全一致(多了/少了斜杠、协议不同等) +- 平台配置未保存或未生效 +- 使用了错误的配置环境(开发/生产) + +### Q3: scope权限在哪里申请? + +**A**: 在WPS365开放平台的"开发配置" > "权限管理"中申请。 + +### Q4: 如何确认参数是否正确? + +**A**: 查看后端日志,会打印完整的授权URL和参数清单。对比WPS365平台配置,确保完全一致。 + +## 调试建议 + +1. **启用DEBUG日志**:在 `application.yml` 中设置日志级别为DEBUG +2. **查看完整授权URL**:复制日志中的授权URL,在浏览器中访问,查看具体错误 +3. **对比官方文档**:查看WPS365官方OAuth文档,确认参数名和格式 +4. **联系WPS365技术支持**:如果所有参数都正确但仍报错,可能是平台问题 + +## 下一步 + +如果按照以上步骤排查后仍然报错,请提供: +1. 后端日志中的完整授权URL和参数清单 +2. WPS365平台配置的回调地址截图 +3. WPS365平台的应用配置截图(隐藏敏感信息) + diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WPS365OAuthServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WPS365OAuthServiceImpl.java index 7110dcc..e151f8b 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WPS365OAuthServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WPS365OAuthServiceImpl.java @@ -59,7 +59,11 @@ public class WPS365OAuthServiceImpl implements IWPS365OAuthService { // 构建授权URL StringBuilder authUrl = new StringBuilder(); authUrl.append(oauthUrl); + + // WPS365可能使用 app_id 而不是 client_id,先尝试 client_id(标准OAuth2参数) + // 如果失败,可能需要改为 app_id authUrl.append("?client_id=").append(appId); + log.debug("授权URL参数 - client_id: {}", appId); // 重要:redirect_uri必须与WPS365开放平台配置的回调地址完全一致 // 包括协议(https)、域名、路径,不能有多余的斜杠 @@ -69,6 +73,11 @@ public class WPS365OAuthServiceImpl implements IWPS365OAuthService { finalRedirectUri = finalRedirectUri.substring(0, finalRedirectUri.length() - 1); } + // 验证redirect_uri不为空 + if (finalRedirectUri == null || finalRedirectUri.isEmpty()) { + throw new RuntimeException("redirect_uri不能为空,请检查application.yml中的wps365.redirect-uri配置"); + } + try { String encodedRedirectUri = java.net.URLEncoder.encode(finalRedirectUri, "UTF-8"); authUrl.append("&redirect_uri=").append(encodedRedirectUri); @@ -77,21 +86,37 @@ public class WPS365OAuthServiceImpl implements IWPS365OAuthService { log.error("URL编码失败", e); authUrl.append("&redirect_uri=").append(finalRedirectUri); } - authUrl.append("&response_type=code"); - // WPS365的scope,根据官方文档设置 - // 注意:scope参数可能需要根据实际申请的权限调整 - authUrl.append("&scope=file.read,ksheet.read,user.info"); - // 添加state参数 + // response_type参数(必需) + authUrl.append("&response_type=code"); + log.debug("授权URL参数 - response_type: code"); + + // scope参数(必需,根据WPS365文档) + String scope = "file.read,ksheet.read,user.info"; + authUrl.append("&scope=").append(scope); + log.debug("授权URL参数 - scope: {}", scope); + + // state参数(推荐,用于防止CSRF攻击) if (state == null || state.trim().isEmpty()) { state = UUID.randomUUID().toString(); } authUrl.append("&state=").append(state); + log.debug("授权URL参数 - state: {}", state); String result = authUrl.toString(); log.info("生成授权URL: {}", result); log.warn("⚠️ 请确保WPS365开放平台配置的回调地址与以下地址完全一致(包括协议、域名、路径):"); log.warn("⚠️ 回调地址: {}", finalRedirectUri); + log.info("📋 授权请求参数清单:"); + log.info(" - client_id: {}", appId); + log.info(" - redirect_uri: {}", finalRedirectUri); + log.info(" - response_type: code"); + log.info(" - scope: {}", scope); + log.info(" - state: {}", state); + log.info("如果仍然报错,请检查:"); + log.info(" 1. WPS365平台配置的回调地址是否与上述redirect_uri完全一致"); + log.info(" 2. 参数名是否正确(WPS365可能使用app_id而不是client_id)"); + log.info(" 3. scope权限是否已在WPS365平台申请"); return result; }