diff --git a/doc/WPS365集成使用说明.md b/doc/WPS365集成使用说明.md index 9a8a11c..0f1a99a 100644 --- a/doc/WPS365集成使用说明.md +++ b/doc/WPS365集成使用说明.md @@ -32,7 +32,8 @@ wps365: # 应用密钥(从WPS365开放平台获取) app-key: YOUR_APP_KEY # 授权回调地址(需要在WPS365开放平台配置) - redirect-uri: https://your-domain.com/jarvis/wps365/oauth/callback + # 注意:使用 /wps365-callback 路径,避免前端路由拦截 + redirect-uri: https://your-domain.com/wps365-callback # API基础地址(一般不需要修改) api-base-url: https://open.wps.cn/api/v1 # OAuth授权地址(一般不需要修改) @@ -43,6 +44,11 @@ wps365: refresh-token-url: https://open.wps.cn/oauth2/v1/token ``` +**重要提示**: +- 回调地址使用 `/wps365-callback` 而不是 `/jarvis/wps365/oauth/callback` +- 这样可以避免前端路由拦截,确保OAuth回调能正常访问 +- 在WPS365开放平台配置时,只需配置域名(如:`jarvis.van333.cn`),回调路径会自动使用配置中的完整URL + ## API接口说明 ### 1. 获取授权URL @@ -67,13 +73,19 @@ window.open(authUrl, '_blank') ### 2. OAuth回调处理 -**接口**: `GET /jarvis/wps365/oauth/callback` +**接口**: `GET /wps365-callback` **参数**: - `code`: 授权码(由WPS365回调时自动传入) - `state`: 状态参数(可选) +- `error`: 错误码(授权失败时) +- `error_description`: 错误描述(授权失败时) -**说明**: 此接口处理WPS365的授权回调,自动获取并保存Token。 +**说明**: +- 此接口处理WPS365的授权回调,自动获取并保存Token +- 返回HTML页面,显示授权结果 +- 使用 `/wps365-callback` 路径避免前端路由拦截 +- 授权成功后会显示成功页面,3秒后自动关闭窗口 ### 3. 获取Token状态 diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/WPS365CallbackController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/WPS365CallbackController.java new file mode 100644 index 0000000..aa7c4cc --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/WPS365CallbackController.java @@ -0,0 +1,169 @@ +package com.ruoyi.web.controller.jarvis; + +import com.ruoyi.common.annotation.Anonymous; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.jarvis.domain.dto.WPS365TokenInfo; +import com.ruoyi.jarvis.service.IWPS365OAuthService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * WPS365 OAuth回调控制器 + * 用于处理OAuth回调,避免前端路由拦截 + * + * @author system + */ +@RestController +@RequestMapping("/wps365-callback") +public class WPS365CallbackController extends BaseController { + + private static final Logger log = LoggerFactory.getLogger(WPS365CallbackController.class); + + @Autowired + private IWPS365OAuthService wps365OAuthService; + + /** + * OAuth回调 - 通过授权码获取访问令牌 + * 路径:/wps365-callback + * 注意:在WPS365开放平台只需配置域名:jarvis.van333.cn(不能包含路径) + * 授权URL中的redirect_uri参数会自动使用配置中的完整URL:https://jarvis.van333.cn/wps365-callback + */ + @Anonymous + @GetMapping(produces = MediaType.TEXT_HTML_VALUE) + public String oauthCallback(@RequestParam(value = "code", required = false) String code, + @RequestParam(value = "state", required = false) String state, + @RequestParam(value = "error", required = false) String error, + @RequestParam(value = "error_description", required = false) String errorDescription) { + try { + // 处理授权错误 + if (error != null) { + log.error("WPS365授权失败 - error: {}, error_description: {}", error, errorDescription); + String errorMsg = errorDescription != null ? errorDescription : error; + return generateCallbackHtml(false, "授权失败: " + errorMsg, null); + } + + // 验证授权码 + if (code == null || code.trim().isEmpty()) { + log.error("授权码为空"); + return generateCallbackHtml(false, "授权码不能为空", null); + } + + log.info("收到WPS365授权回调 - code: {}, state: {}", code, state); + + // 使用授权码换取access_token + WPS365TokenInfo tokenInfo = wps365OAuthService.getAccessTokenByCode(code); + + // 验证返回的token信息 + if (tokenInfo == null || tokenInfo.getAccessToken() == null) { + log.error("获取访问令牌失败 - tokenInfo: {}", tokenInfo); + return generateCallbackHtml(false, "获取访问令牌失败,响应数据格式不正确", null); + } + + log.info("成功获取访问令牌 - userId: {}, access_token: {}", + tokenInfo.getUserId(), + tokenInfo.getAccessToken() != null ? tokenInfo.getAccessToken().substring(0, 20) + "..." : "null"); + + // 自动保存token到后端 + try { + if (tokenInfo.getUserId() != null) { + wps365OAuthService.saveToken(tokenInfo.getUserId(), tokenInfo); + log.info("访问令牌已自动保存到后端缓存 - userId: {}", tokenInfo.getUserId()); + } else { + log.warn("userId为空,无法保存Token"); + return generateCallbackHtml(false, "获取用户ID失败,无法保存Token", null); + } + } catch (Exception e) { + log.error("保存访问令牌失败", e); + return generateCallbackHtml(false, "保存访问令牌失败: " + e.getMessage(), null); + } + + return generateCallbackHtml(true, "授权成功,访问令牌已自动保存", tokenInfo); + } catch (Exception e) { + log.error("OAuth回调处理失败", e); + return generateCallbackHtml(false, "授权失败: " + e.getMessage(), null); + } + } + + /** + * 生成回调HTML页面 + */ + private String generateCallbackHtml(boolean success, String message, WPS365TokenInfo tokenInfo) { + StringBuilder html = new StringBuilder(); + html.append(""); + html.append(""); + html.append("
"); + html.append(""); + html.append(""); + html.append("窗口将在3秒后自动关闭...
"); + html.append("