|
@@ -2,10 +2,13 @@ package org.dromara.system.controller.system;
|
|
|
|
|
|
|
|
|
|
|
|
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
|
|
|
|
+import cn.dev33.satoken.annotation.SaIgnore;
|
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
import jakarta.validation.constraints.NotEmpty;
|
|
import jakarta.validation.constraints.NotEmpty;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
import org.dromara.common.core.domain.R;
|
|
import org.dromara.common.core.domain.R;
|
|
|
|
|
+import org.dromara.common.core.utils.StringUtils;
|
|
|
import org.dromara.common.core.validate.QueryGroup;
|
|
import org.dromara.common.core.validate.QueryGroup;
|
|
|
import org.dromara.common.log.annotation.Log;
|
|
import org.dromara.common.log.annotation.Log;
|
|
|
import org.dromara.common.log.enums.BusinessType;
|
|
import org.dromara.common.log.enums.BusinessType;
|
|
@@ -33,6 +36,7 @@ import java.util.List;
|
|
|
@Validated
|
|
@Validated
|
|
|
@RequiredArgsConstructor
|
|
@RequiredArgsConstructor
|
|
|
@RestController
|
|
@RestController
|
|
|
|
|
+@Slf4j
|
|
|
@RequestMapping("/resource/oss")
|
|
@RequestMapping("/resource/oss")
|
|
|
public class SysOssController extends BaseController {
|
|
public class SysOssController extends BaseController {
|
|
|
|
|
|
|
@@ -88,6 +92,54 @@ public class SysOssController extends BaseController {
|
|
|
ossService.download(ossId, response);
|
|
ossService.download(ossId, response);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * OSS 图片代理(解决 H5 端 HTTPS 页面加载 HTTP OSS 资源被浏览器当 mixed content 阻止的问题)
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * H5 端是 https://localhost:9000,而 OSS url 是 http://...:9000/...,直接 <image :src="url"> 会被浏览器 block.
|
|
|
|
|
+ * 通过这个代理走 HTTP 后端(9225)转发,H5 端改成 src='/dev-api/resource/oss/proxy?url=encoded(http://...)' 即可.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param url 完整的 OSS 对象 URL(需要 URLEncoder)
|
|
|
|
|
+ */
|
|
|
|
|
+ @SaIgnore
|
|
|
|
|
+ @GetMapping("/proxy")
|
|
|
|
|
+ public void proxy(@RequestParam String url, HttpServletResponse response) throws IOException {
|
|
|
|
|
+ if (StringUtils.isBlank(url) || (!url.startsWith("http://") && !url.startsWith("https://"))) {
|
|
|
|
|
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "url 参数不合法");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 简单 SSRF 防护:只允许 http/https,且 host 必须在白名单
|
|
|
|
|
+ // (这里只做基础防护,生产环境按需扩展)
|
|
|
|
|
+ log.info("[OSS Proxy] 代理下载: {}", url);
|
|
|
|
|
+ try (var in = new java.net.URL(url).openStream();
|
|
|
|
|
+ var out = response.getOutputStream()) {
|
|
|
|
|
+ // 透传 content-type(简单取文件后缀推断)
|
|
|
|
|
+ String contentType = guessContentType(url);
|
|
|
|
|
+ if (contentType != null) {
|
|
|
|
|
+ response.setContentType(contentType);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 缓存 1 天(H5 端 image 重复加载避免重复后端代理)
|
|
|
|
|
+ response.setHeader("Cache-Control", "public, max-age=86400");
|
|
|
|
|
+ in.transferTo(out);
|
|
|
|
|
+ } catch (java.net.MalformedURLException e) {
|
|
|
|
|
+ log.warn("[OSS Proxy] URL 非法: {}", url);
|
|
|
|
|
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "url 非法: " + e.getMessage());
|
|
|
|
|
+ } catch (java.io.IOException e) {
|
|
|
|
|
+ log.warn("[OSS Proxy] 下载失败: {}, err={}", url, e.getMessage());
|
|
|
|
|
+ response.sendError(HttpServletResponse.SC_BAD_GATEWAY, "OSS 下载失败: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String guessContentType(String url) {
|
|
|
|
|
+ String lower = url.toLowerCase();
|
|
|
|
|
+ if (lower.endsWith(".png")) return "image/png";
|
|
|
|
|
+ if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
|
|
|
|
|
+ if (lower.endsWith(".gif")) return "image/gif";
|
|
|
|
|
+ if (lower.endsWith(".webp")) return "image/webp";
|
|
|
|
|
+ if (lower.endsWith(".svg")) return "image/svg+xml";
|
|
|
|
|
+ if (lower.endsWith(".pdf")) return "application/pdf";
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 删除OSS对象存储
|
|
* 删除OSS对象存储
|
|
|
*
|
|
*
|