This commit is contained in:
Leo
2026-01-15 20:37:49 +08:00
parent 8802e68106
commit 7f7bec8d29
2 changed files with 183 additions and 5 deletions

View File

@@ -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. **应用IDAppId** 是否与配置文件中的 `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平台的应用配置截图隐藏敏感信息

View File

@@ -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;
}