# 腾讯文档 API 鉴权修复指南 ## 关键发现 根据腾讯文档官方 API 文档,发现了之前鉴权方式的重大错误: ### 正确的鉴权方式 腾讯文档 V3 API 需要**三个请求头**进行鉴权: ```http Access-Token: {访问令牌} Client-Id: {应用ID} Open-Id: {开放平台用户ID} ``` **而不是**: ```http Authorization: Bearer {访问令牌} ❌ 错误! ``` ## 推荐方案:使用应用级账号 Token ### 什么是应用级账号 Token? - 不需要用户授权流程 - 直接使用 `client_id` 和 `client_secret` 获取 - 响应包含所有需要的信息 ### API 接口 **请求:** ```http GET https://docs.qq.com/oauth/v2/app-account-token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET ``` **响应:** ```json { "access_token": "ACCESSTOKENEXAMPLE", "token_type": "Bearer", "refresh_token": "REFRESHTOKENEXAMPLE", "expires_in": 259200, "scope": "scope.file.editable,scope.folder.creatable", "user_id": "bcb50c8a4b724d86bbcf6fc64c5e2b22" } ``` ### 字段映射 | 响应字段 | 对应请求头 | 说明 | |---------|-----------|------| | `access_token` | `Access-Token` | 访问令牌 | | 请求参数 `client_id` | `Client-Id` | 应用ID | | `user_id` | `Open-Id` | 开放平台用户ID(关键!) | ## 完整的 API 调用流程 ### 步骤1:获取应用级账号 Token ```java JSONObject tokenInfo = TencentDocApiUtil.getAppAccountToken(appId, appSecret); String accessToken = tokenInfo.getString("access_token"); String openId = tokenInfo.getString("user_id"); // 这就是 Open-Id! String clientId = appId; // Client-Id 就是 appId ``` ### 步骤2:调用业务 API ```java // 设置请求头 conn.setRequestProperty("Access-Token", accessToken); conn.setRequestProperty("Client-Id", clientId); conn.setRequestProperty("Open-Id", openId); conn.setRequestProperty("Content-Type", "application/json"); ``` ### 步骤3:发送请求 ```http GET https://docs.qq.com/openapi/spreadsheet/v3/files/{fileId}/{sheetId}/A1:Z100 Access-Token: ACCESSTOKENEXAMPLE Client-Id: YOUR_CLIENT_ID Open-Id: bcb50c8a4b724d86bbcf6fc64c5e2b22 Content-Type: application/json ``` ## 代码修改方案 ### 方案 A:简单封装(推荐) 在 Service 层创建一个包装类来管理鉴权信息: ```java public class TencentDocAuth { private String accessToken; private String clientId; private String openId; private long expiresAt; // 获取或刷新 Token public static TencentDocAuth getAuth(String appId, String appSecret) { JSONObject tokenInfo = TencentDocApiUtil.getAppAccountToken(appId, appSecret); TencentDocAuth auth = new TencentDocAuth(); auth.accessToken = tokenInfo.getString("access_token"); auth.openId = tokenInfo.getString("user_id"); auth.clientId = appId; auth.expiresAt = System.currentTimeMillis() + tokenInfo.getIntValue("expires_in") * 1000; return auth; } // Getters... } ``` ### 方案 B:修改现有方法签名 修改 `callApi` 方法,添加必要的参数: ```java public static JSONObject callApi(String accessToken, String clientId, String openId, String apiUrl, String method, String body) { conn.setRequestProperty("Access-Token", accessToken); conn.setRequestProperty("Client-Id", clientId); conn.setRequestProperty("Open-Id", openId); // ... } ``` 然后更新所有调用此方法的地方。 ## 实现步骤 ### 1. 添加获取应用级账号 Token 的方法 ✅ 已在 `TencentDocApiUtil.java` 中添加: ```java public static JSONObject getAppAccountToken(String appId, String appSecret) ``` ### 2. 修改 callApi 方法 ✅ 已更新为: ```java public static JSONObject callApi(String accessToken, String clientId, String openId, String apiUrl, String method, String body) ``` ### 3. 更新所有调用点(待完成) 需要更新以下方法: - `readSheetData()` - `writeSheetData()` - `appendSheetData()` - `getFileInfo()` - `getSheetList()` 以及所有调用这些方法的 Service 类。 ## 测试验证 ### 1. 获取应用级账号 Token ```java JSONObject tokenInfo = TencentDocApiUtil.getAppAccountToken( "YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET" ); System.out.println("Access Token: " + tokenInfo.getString("access_token")); System.out.println("Open-Id: " + tokenInfo.getString("user_id")); ``` ### 2. 调用表格 API ```java String accessToken = tokenInfo.getString("access_token"); String clientId = "YOUR_CLIENT_ID"; String openId = tokenInfo.getString("user_id"); JSONObject result = TencentDocApiUtil.readSheetData( accessToken, clientId, openId, "YOUR_FILE_ID", "SHEET_ID", "A1:Z10", "https://docs.qq.com/openapi/spreadsheet/v3" ); ``` ## 注意事项 ### 1. Token 有效期 应用级账号 Token 默认有效期为 3 天(259200秒),需要定期刷新。 ### 2. 存储安全 - `client_secret` 必须保密 - Token 应该缓存并在过期前刷新 - 不要在日志中打印完整的 Token ### 3. 权限范围 应用级账号的权限取决于申请时的 scope: - `scope.sheet` - 读取表格 - `scope.sheet.editable` - 编辑表格 - `scope.file.editable` - 编辑文件 - `scope.folder.creatable` - 创建文件夹 ## 错误排查 ### 401 Unauthorized - 检查 Access-Token 是否正确 - 检查 Token 是否过期 - 检查是否包含所有三个请求头 ### 403 Forbidden - 检查应用是否有相应的权限 (scope) - 检查 Open-Id 是否正确 ### 404 Not Found - 检查 URL 路径是否正确 - 确认基础 URL 为 `https://docs.qq.com/openapi/spreadsheet/v3` - 确认路径格式为 `/files/{fileId}/...` ## 参考文档 - [批量更新接口](https://docs.qq.com/open/document/app/openapi/v3/sheet/batchUpdate.html) - [获取应用级账号 Token](https://docs.qq.com/open/document/app/oauth2/app-account-token.html) - [请求头部说明](https://docs.qq.com/open/document/app/openapi/v3/) --- **更新时间**:2025-11-05 **状态**:部分完成,需要更新所有调用点