From d175777d75bf4e1e6f17963acd9a579b8835958f Mon Sep 17 00:00:00 2001 From: gouki Date: Tue, 11 Aug 2026 21:23:09 +0000 Subject: [PATCH] =?UTF-8?q?fix(admin):=20=E6=B5=8F=E8=A7=88=E5=99=A8?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E8=AE=BF=E9=97=AE=E5=90=8E=E5=8F=B0=E6=97=B6?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E7=99=BB=E5=BD=95=E9=A1=B5=E8=80=8C=E9=9D=9E?= =?UTF-8?q?401=20JSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AdminAuth 中间件:GET 页面请求未登录时返回 login 页,API 请求仍返回 401 - 新增 Login.js 登录页组件(密码输入 + 登录后跳回原页面) - index.html 注册 login 页面路由 --- server/internal/middleware/middleware.go | 27 ++++++---- server/web/index.html | 1 + server/web/static/js/pages/Login.js | 68 ++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 server/web/static/js/pages/Login.js diff --git a/server/internal/middleware/middleware.go b/server/internal/middleware/middleware.go index 7f97609..f7df354 100644 --- a/server/internal/middleware/middleware.go +++ b/server/internal/middleware/middleware.go @@ -104,6 +104,7 @@ func Auth() gin.HandlerFunc { } // AdminAuth 管理员认证中间件:要求携带 role=admin 的 JWT(Authorization 头或 HttpOnly Cookie) +// 浏览器导航(GET 页面请求)未登录时渲染登录页;API 请求未登录时返回 401 JSON func AdminAuth() gin.HandlerFunc { return func(c *gin.Context) { tokenString := "" @@ -115,18 +116,24 @@ func AdminAuth() gin.HandlerFunc { tokenString, _ = c.Cookie(service.AdminTokenCookie) } - if tokenString == "" { - c.JSON(http.StatusUnauthorized, gin.H{ - "code": 401, - "msg": "需要管理员权限", - }) - c.Abort() - return + authed := false + if tokenString != "" { + cfg := config.Load() + userService := service.NewUserService() + authed = userService.IsAdminToken(tokenString, cfg.JWT.Secret) } - cfg := config.Load() - userService := service.NewUserService() - if !userService.IsAdminToken(tokenString, cfg.JWT.Secret) { + if !authed { + // 页面导航(GET 且非 /admin/api/):返回登录页 + if c.Request.Method == http.MethodGet && !strings.HasPrefix(c.Request.URL.Path, "/admin/api/") { + c.HTML(http.StatusOK, "index.html", gin.H{ + "title": "管理员登录", + "page": "login", + "url": c.Request.URL.Path, + }) + c.Abort() + return + } c.JSON(http.StatusUnauthorized, gin.H{ "code": 401, "msg": "需要管理员权限", diff --git a/server/web/index.html b/server/web/index.html index c03684f..37192e1 100644 --- a/server/web/index.html +++ b/server/web/index.html @@ -19,6 +19,7 @@ createInertiaApp({ resolve: name => { const pages = { + login: () => import('/static/js/pages/Login.js'), dashboard: () => import('/static/js/pages/Dashboard.js'), users: () => import('/static/js/pages/Users.js'), orders: () => import('/static/js/pages/Orders.js'), diff --git a/server/web/static/js/pages/Login.js b/server/web/static/js/pages/Login.js new file mode 100644 index 0000000..a6db795 --- /dev/null +++ b/server/web/static/js/pages/Login.js @@ -0,0 +1,68 @@ +// Login 管理员登录页 +export default { + template: ` +
+
+
+

祈福小助手

+

管理后台登录

+
+
+
+ + +
+
{{ error }}
+ +
+
+
+ `, + data() { + return { + password: '', + loading: false, + error: '' + }; + }, + methods: { + async submit() { + if (!this.password || this.loading) return; + this.loading = true; + this.error = ''; + try { + const res = await fetch('/admin/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ password: this.password }) + }); + const data = await res.json(); + if (data.code === 0) { + // Cookie 已由服务端写入,跳回原本要访问的页面 + window.location.href = window.location.pathname === '/admin/login' + ? '/admin/' + : window.location.pathname; + } else { + this.error = data.msg || '登录失败'; + } + } catch (e) { + this.error = '网络错误,请重试'; + } finally { + this.loading = false; + } + } + } +};