Compare commits
2 Commits
9bb7cfc7fb
...
ef286d3bd2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef286d3bd2 | ||
|
|
184a53005d |
@@ -37,6 +37,18 @@ public class KdocsCallbackController extends BaseController {
|
|||||||
return handleOAuthCallback(code, state, error, errorDescription);
|
return handleOAuthCallback(code, state, error, errorDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部分开放平台校验可能使用 POST。
|
||||||
|
*/
|
||||||
|
@Anonymous
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<?> oauthCallbackPost(@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) {
|
||||||
|
return handleOAuthCallback(code, state, error, errorDescription);
|
||||||
|
}
|
||||||
|
|
||||||
private ResponseEntity<?> handleOAuthCallback(String code, String state, String error, String errorDescription) {
|
private ResponseEntity<?> handleOAuthCallback(String code, String state, String error, String errorDescription) {
|
||||||
try {
|
try {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
@@ -44,8 +56,9 @@ public class KdocsCallbackController extends BaseController {
|
|||||||
log.error("金山文档授权失败: {}", msg);
|
log.error("金山文档授权失败: {}", msg);
|
||||||
return htmlPage(false, "授权失败: " + msg, null);
|
return htmlPage(false, "授权失败: " + msg, null);
|
||||||
}
|
}
|
||||||
|
// 无 code:多为平台校验回调可达性,或用户直接打开本地址(非授权失败)
|
||||||
if (StringUtils.isBlank(code)) {
|
if (StringUtils.isBlank(code)) {
|
||||||
return htmlPage(false, "缺少授权码 code", null);
|
return callbackEndpointInfoPage();
|
||||||
}
|
}
|
||||||
log.info("金山文档授权回调 code 已收到 state={}", state);
|
log.info("金山文档授权回调 code 已收到 state={}", state);
|
||||||
KdocsTokenInfo tokenInfo = kdocsOAuthService.getAccessTokenByCode(code);
|
KdocsTokenInfo tokenInfo = kdocsOAuthService.getAccessTokenByCode(code);
|
||||||
@@ -63,7 +76,7 @@ public class KdocsCallbackController extends BaseController {
|
|||||||
|
|
||||||
private ResponseEntity<String> htmlPage(boolean success, String message, KdocsTokenInfo tokenInfo) {
|
private ResponseEntity<String> htmlPage(boolean success, String message, KdocsTokenInfo tokenInfo) {
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.TEXT_HTML);
|
headers.setContentType(MediaType.parseMediaType("text/html;charset=UTF-8"));
|
||||||
String esc = message.replace("\\", "\\\\").replace("'", "\\'").replace("\n", "\\n").replace("\r", "\\r");
|
String esc = message.replace("\\", "\\\\").replace("'", "\\'").replace("\n", "\\n").replace("\r", "\\r");
|
||||||
String uid = tokenInfo != null && tokenInfo.getUserId() != null ? tokenInfo.getUserId().replace("\\", "\\\\").replace("'", "\\'") : "";
|
String uid = tokenInfo != null && tokenInfo.getUserId() != null ? tokenInfo.getUserId().replace("\\", "\\\\").replace("'", "\\'") : "";
|
||||||
StringBuilder html = new StringBuilder();
|
StringBuilder html = new StringBuilder();
|
||||||
@@ -83,4 +96,11 @@ public class KdocsCallbackController extends BaseController {
|
|||||||
html.append("</script></body></html>");
|
html.append("</script></body></html>");
|
||||||
return new ResponseEntity<>(html.toString(), headers, HttpStatus.OK);
|
return new ResponseEntity<>(html.toString(), headers, HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无授权参数时的占位页:HTTP 200,避免被误判为「回调不可用」,也不向 opener 误发失败消息。
|
||||||
|
*/
|
||||||
|
private ResponseEntity<String> callbackEndpointInfoPage() {
|
||||||
|
return KdocsCallbackProbeResponses.callbackReadyPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.ruoyi.web.controller.jarvis;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开放平台校验回调 URL 时多为 GET、无 code,需直接 200;勿对校验请求返回 302。
|
||||||
|
*/
|
||||||
|
public final class KdocsCallbackProbeResponses {
|
||||||
|
|
||||||
|
private KdocsCallbackProbeResponses() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final MediaType HTML_UTF8 = MediaType.parseMediaType("text/html;charset=UTF-8");
|
||||||
|
|
||||||
|
private static final String BODY = "<!DOCTYPE html><html lang='zh-CN'><head><meta charset='UTF-8'><meta name='robots' content='noindex'>"
|
||||||
|
+ "<title>金山文档授权回调</title></head>"
|
||||||
|
+ "<body style='font-family:sans-serif;text-align:center;padding:40px;color:#333'>"
|
||||||
|
+ "<h2>金山文档授权回调</h2>"
|
||||||
|
+ "<p>此地址用于 OAuth 授权完成后的跳转,请勿直接收藏或打开。</p>"
|
||||||
|
+ "<p>请在系统中点击「连接金山文档」或「授权」后,由金山文档页面自动跳转到此处。</p>"
|
||||||
|
+ "</body></html>";
|
||||||
|
|
||||||
|
public static ResponseEntity<String> callbackReadyPage() {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(HTML_UTF8);
|
||||||
|
return new ResponseEntity<>(BODY, headers, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.ruoyi.web.controller.jarvis;
|
||||||
|
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反向代理后拼浏览器可访问的绝对 URL(OAuth 302 用)。
|
||||||
|
*/
|
||||||
|
public final class KdocsCallbackUrlBuilder {
|
||||||
|
|
||||||
|
private KdocsCallbackUrlBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String absoluteKdocsCallback(HttpServletRequest request, String queryString) {
|
||||||
|
String scheme = request.getHeader("X-Forwarded-Proto");
|
||||||
|
if (StringUtils.isBlank(scheme)) {
|
||||||
|
scheme = request.getScheme();
|
||||||
|
} else if (scheme.contains(",")) {
|
||||||
|
scheme = scheme.substring(0, scheme.indexOf(',')).trim();
|
||||||
|
}
|
||||||
|
String host = request.getHeader("Host");
|
||||||
|
if (StringUtils.isBlank(host)) {
|
||||||
|
int port = request.getServerPort();
|
||||||
|
host = request.getServerName();
|
||||||
|
if (port != 80 && port != 443) {
|
||||||
|
host = host + ":" + port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(scheme).append("://").append(host).append("/kdocs-callback");
|
||||||
|
if (StringUtils.isNotBlank(queryString)) {
|
||||||
|
sb.append('?').append(queryString);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.ruoyi.web.controller.jarvis;
|
||||||
|
|
||||||
|
import com.ruoyi.common.annotation.Anonymous;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旧回调 /wps365-callback:平台校验多为「GET、无 code」须直接 200;真实授权带 code/error 时再 302 到 /kdocs-callback。
|
||||||
|
*/
|
||||||
|
@Anonymous
|
||||||
|
@RestController
|
||||||
|
public class Wps365ToKdocsCallbackRedirectController {
|
||||||
|
|
||||||
|
@Anonymous
|
||||||
|
@GetMapping("/wps365-callback")
|
||||||
|
public ResponseEntity<?> wps365Get(HttpServletRequest request,
|
||||||
|
@RequestParam(value = "code", required = false) String code,
|
||||||
|
@RequestParam(value = "error", required = false) String error) {
|
||||||
|
return handleWps365(request, code, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部分校验或代理可能使用 POST。
|
||||||
|
*/
|
||||||
|
@Anonymous
|
||||||
|
@PostMapping("/wps365-callback")
|
||||||
|
public ResponseEntity<?> wps365Post(HttpServletRequest request,
|
||||||
|
@RequestParam(value = "code", required = false) String code,
|
||||||
|
@RequestParam(value = "error", required = false) String error) {
|
||||||
|
return handleWps365(request, code, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseEntity<?> handleWps365(HttpServletRequest request, String code, String error) {
|
||||||
|
if (StringUtils.isBlank(code) && StringUtils.isBlank(error)) {
|
||||||
|
return KdocsCallbackProbeResponses.callbackReadyPage();
|
||||||
|
}
|
||||||
|
String q = request.getQueryString();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setLocation(URI.create(KdocsCallbackUrlBuilder.absoluteKdocsCallback(request, q)));
|
||||||
|
return new ResponseEntity<>(null, headers, HttpStatus.FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,6 +118,10 @@ public class SecurityConfig
|
|||||||
.antMatchers("/jarvis/tendoc/oauth/callback").permitAll()
|
.antMatchers("/jarvis/tendoc/oauth/callback").permitAll()
|
||||||
// 腾讯文档OAuth回调接口(备用路径),允许匿名访问
|
// 腾讯文档OAuth回调接口(备用路径),允许匿名访问
|
||||||
.antMatchers("/tendoc-callback").permitAll()
|
.antMatchers("/tendoc-callback").permitAll()
|
||||||
|
// 金山文档 OAuth 回调(与 @Anonymous 双保险,避免未扫描进白名单时 401)
|
||||||
|
.antMatchers("/kdocs-callback").permitAll()
|
||||||
|
// 旧 WPS 回调路径:重定向到新路径,便于后台仍登记旧 URL 时可用
|
||||||
|
.antMatchers("/wps365-callback").permitAll()
|
||||||
// 静态资源,可匿名访问
|
// 静态资源,可匿名访问
|
||||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
||||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||||
|
|||||||
Reference in New Issue
Block a user