From 4ad3fbfca877943b10c809ef98a8458e1ff043db Mon Sep 17 00:00:00 2001 From: qing <1776177662@qq.com> Date: Tue, 28 Jul 2026 09:31:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=85=AC=E5=BC=80?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=9B=A0=E6=97=A7=20Cookie=20=E9=AA=8C?= =?UTF-8?q?=E7=AD=BE=E5=A4=B1=E8=B4=A5=E8=AF=AF=E8=BF=94=E5=9B=9E=20401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 浏览器会自动给每个请求携带 q4_token,gateway 重启轮换内存 RSA 密钥后旧凭证验签失败,导致无需登录的公开页面也 401。代理层改为仅对需鉴权目标校验凭证,公开目标跳过;前端遇 401 自动跳转登录页自愈。 --- gateway/src/main.cpp | 35 ++++++++++++++++++++++------------- static/public/js/dnfs.js | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/gateway/src/main.cpp b/gateway/src/main.cpp index dc0e1ac..5631873 100644 --- a/gateway/src/main.cpp +++ b/gateway/src/main.cpp @@ -26,7 +26,7 @@ using namespace qing; namespace json = boost::json; namespace po = boost::program_options; -constexpr const char *_VER = "0.4.1"; +constexpr const char *_VER = "0.4.2"; ////////////////////////////////// #include @@ -966,20 +966,26 @@ http::response handleProxy( } if (raw.empty() && !flag) THROW_EX_CUSTOM(HttpException, 2301, "Unauthorization", 401, "*"); - if (raw.substr(0, 7) == "Bearer ") { - raw = raw.substr(7, raw.size() - 7); - size_t idx = raw.find("_"); - if (idx == std::string::npos) - THROW_EX_CUSTOM(HttpException, 2301, "Unauthorization", 400, "*"); - std::string data = raw.substr(0, idx); - std::string sign = raw.substr(idx+1, raw.size()-idx-1); - auth = Base64::base64_decode_to_string(data); - if (!_PUBL.Verify(auth, sign)) - THROW_EX_CUSTOM(HttpException, 2301, "Unauthorization", 401, "*"); - } - /* 是否过期 */ if (!flag) { + /* 仅在需要鉴权的目标上校验凭证。 + * 默认目标(公开静态资源)必须跳过校验: + * 浏览器会给每个请求自动携带 q4_token Cookie, + * gateway 重启(内存 RSA 密钥对轮换)或 Token 过期后, + * 旧 Cookie 验签失败会让公开页面也误返回 401 */ + if (raw.substr(0, 7) == "Bearer ") { + raw = raw.substr(7, raw.size() - 7); + size_t idx = raw.find("_"); + if (idx == std::string::npos) + THROW_EX_CUSTOM(HttpException, 2301, "Unauthorization", 400, "*"); + std::string data = raw.substr(0, idx); + std::string sign = raw.substr(idx+1, raw.size()-idx-1); + auth = Base64::base64_decode_to_string(data); + if (!_PUBL.Verify(auth, sign)) + THROW_EX_CUSTOM(HttpException, 2301, "Unauthorization", 401, "*"); + } + + /* 是否过期 */ try { jv_t = json::parse(auth); } catch (const boost::wrapexcept& e) { THROW_EX_CUSTOM(HttpException, 2302, "Bad token", 400, "*"); @@ -995,6 +1001,9 @@ http::response handleProxy( auto expire_tp = *created_tp + std::chrono::seconds(keep_time_val); if (now > expire_tp) THROW_EX_CUSTOM(HttpException, 2000, "Authorization Expired", 401, "*"); } + } else { + /* 公开目标不做凭证校验,也不向下游注入 Authorization */ + cookie_token = ""; } } diff --git a/static/public/js/dnfs.js b/static/public/js/dnfs.js index 5fb4497..0af3b5f 100644 --- a/static/public/js/dnfs.js +++ b/static/public/js/dnfs.js @@ -28,6 +28,12 @@ async function getNode(id) { throw new Error('服务器响应格式异常,请稍后重试'); } + if (res.status === 401) { + // 凭证失效(过期或网关重启),跳转重新登录 + location.href = '/login.html'; + return; + } + if (!res.ok) { throw new Error(result.message || `获取节点失败(HTTP ${res.status})`); } @@ -80,6 +86,12 @@ async function addNode(pid, title, content) { throw new Error('服务器响应格式异常,请稍后重试'); } + if (res.status === 401) { + // 凭证失效(过期或网关重启),跳转重新登录 + location.href = '/login.html'; + return; + } + if (!res.ok) { throw new Error(`添加节点失败(HTTP ${res.status})`); } @@ -133,6 +145,12 @@ async function deleteNode(id) { throw new Error('服务器响应格式异常,请稍后重试'); } + if (res.status === 401) { + // 凭证失效(过期或网关重启),跳转重新登录 + location.href = '/login.html'; + return; + } + if (!res.ok) { throw new Error(`删除节点失败(HTTP ${res.status})`); }