From 03ee39fccf3ddadbd04ec447a723fc3df96a8928 Mon Sep 17 00:00:00 2001 From: engigu Date: Tue, 10 Mar 2026 16:21:09 +0800 Subject: [PATCH] feat: update openapi page logic --- internal/middleware/auth.go | 40 +++++++++++++++++-------- internal/router/openapi_routes.go | 8 ++--- web/src/views/settings/SiteSettings.vue | 15 ++++++++-- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go index 54b83ce..e424264 100644 --- a/internal/middleware/auth.go +++ b/internal/middleware/auth.go @@ -182,23 +182,39 @@ func SwaggerAuth() gin.HandlerFunc { } } + // 获取请求中携带的凭证 + // 1. URL 参数 token + // 2. Cookie 中的 openapi_token + // 3. HTTP Basic Auth + tokenQuery := c.Query("token") + tokenCookie, _ := c.Cookie("openapi_token") _, password, hasAuth := c.Request.BasicAuth() - // 允许使用任意用户名,但密码必须匹配 OpenAPI Token - if hasAuth && password == tokenConfig.Token && tokenConfig.Token != "" { + + var providedToken string + if tokenQuery != "" { + providedToken = tokenQuery + } else if tokenCookie != "" { + providedToken = tokenCookie + } else if hasAuth { + providedToken = password + } + + // 检查提供的 token 是否匹配 + if providedToken != "" && providedToken == tokenConfig.Token { + // 如果是通过 url 参数进来的,自动将其种入 Cookie,便于后续加载静态资源 (如 json) + if tokenQuery != "" { + c.SetCookie("openapi_token", providedToken, 86400, "/openapi", "", false, false) + } c.Next() return } - // 未提供认证,触发浏览器登录弹窗 - if !hasAuth { - c.Header("WWW-Authenticate", `Basic realm="OpenAPI Access Token (Any username)"`) - c.Status(http.StatusUnauthorized) - c.Abort() - return - } - - // 认证失败 (密码错误),返回 404 隐藏路由 - c.Status(http.StatusNotFound) + // 验证失败,不再返回 WWW-Authenticate 头触发浏览器反人类原生弹窗 + // 我们返回 401 的 JSON 或纯文本结构,以便由调用方自行接管鉴权逻辑 + c.JSON(http.StatusUnauthorized, gin.H{ + "code": 401, + "msg": "OpenAPI 访问未授权或 Token 错误", + }) c.Abort() } } diff --git a/internal/router/openapi_routes.go b/internal/router/openapi_routes.go index 16020b4..bb8256c 100644 --- a/internal/router/openapi_routes.go +++ b/internal/router/openapi_routes.go @@ -40,13 +40,9 @@ func initOpenAPIRoutes(root *gin.RouterGroup, urlPrefix string) { return } - // 执行认证 - middleware.SwaggerAuth()(c) + // 执行主站 Cookie 认证 + middleware.AuthRequired()(c) if c.IsAborted() { - // 如果认证失败(且被中间件置为 404,如密码错误且我们想要隐藏它) - if c.Writer.Status() == http.StatusNotFound { - serveSPA(c, urlPrefix, 404) - } return } diff --git a/web/src/views/settings/SiteSettings.vue b/web/src/views/settings/SiteSettings.vue index 1a7ab16..14f8231 100644 --- a/web/src/views/settings/SiteSettings.vue +++ b/web/src/views/settings/SiteSettings.vue @@ -112,6 +112,14 @@ async function copyOpenapiToken() { } } +function openSwaggerDocs() { + if (!form.value.openapi_enabled) { + toast.error('必须先开启 OpenAPI 才能查看接口文档页面') + return + } + window.open(`${baseUrl}/openapi/index.html`, '_blank') +} + onMounted(loadSettings) @@ -240,20 +248,20 @@ onMounted(loadSettings) class="font-normal text-xs bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20 whitespace-nowrap">推荐方式
- 查看接口文档
- +

开启全局 OpenAPI 直接访问能力,配置后可通过请求头 Authorization: Bearer <在此生成的Token> - 无需登录直接调用系统的所有接口,请妥善保管并设置合理的有效期。注意:必须先开启鉴权开关才能查看接口文档页面和进行调用。

+ 以第三方身份调用系统的所有接口,请妥善保管 Token 并设置合理的有效期。注意:必须先开启本功能才能查看接口文档页面和对接调用。

@@ -303,5 +311,6 @@ onMounted(loadSettings) +