From 5de6cfc9ded19133f6fd6b085abc932fcb35953f Mon Sep 17 00:00:00 2001 From: "liweiliang0905@gmail.com" Date: Thu, 22 Jan 2026 15:17:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AE=A1=E7=90=86=E5=90=8E=E5=8F=B0=E5=85=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在账户区域添加"进入管理后台"按钮(仅管理员可见) - 使用 localStorage 缓存用户信息确保显示正确 Co-Authored-By: Claude Opus 4.5 --- README.md | 36 +++++++++++++++++- .../core/__pycache__/auth.cpython-313.pyc | Bin 3113 -> 3704 bytes .../web/__pycache__/app.cpython-313.pyc | Bin 278939 -> 297647 bytes src/vitals/web/app.py | 30 +++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 41fb4a3..8bf9b54 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ - **BMI 计算** - 自动计算并显示健康状态(偏瘦/正常/偏胖/肥胖) - **用户切换** - 支持多用户数据隔离 - **数据管理** - 按日期范围或数据类型清除数据 -- **JWT 认证** - 安全的 Token 认证机制 +- **JWT 认证** - HTTPOnly Cookie + Authorization Header 混合认证 +- **记住我** - 可选 1 天或 30 天登录有效期 - **邀请码注册** - 通过邀请码控制用户注册 - **管理员面板** - 用户管理、邀请码管理 @@ -93,8 +94,9 @@ uvicorn vitals.web.app:app --host 0.0.0.0 --port 8080 | 端点 | 方法 | 说明 | |------|------|------| -| `/api/auth/login` | POST | 用户登录,返回 JWT Token | +| `/api/auth/login` | POST | 用户登录,返回 JWT Token + 设置 Cookie | | `/api/auth/register` | POST | 用户注册(需邀请码) | +| `/api/auth/logout` | POST | 用户登出,清除 Cookie | | `/api/auth/me` | GET | 获取当前用户信息 | ### 管理员 @@ -428,6 +430,36 @@ vitals/ - [ ] 部分页面在小屏幕上布局需要调整 - [ ] 书籍封面搜索有时无法找到匹配结果 +## 更新日志 + +### 2026-01-22 + +#### 🔐 混合认证方案优化 +- 修改 login/register API 使用 JSONResponse 正确设置 Cookie +- 添加 `path="/"` 确保 Cookie 在所有路径可用 +- 前端同时使用 localStorage token 进行 API 认证 +- 修复登录后闪屏返回登录页的问题 + +#### ✨ 登录功能全面升级 +- **服务端认证中间件** - 未登录用户自动重定向到登录页 +- **HTTPOnly Cookie** - 使用 HTTPOnly Cookie 存储 token(比 localStorage 更安全) +- **"记住我"功能** - 勾选:30 天有效期,不勾选:1 天有效期 +- **登出 API** - 新增 `/api/auth/logout` 接口 +- **登录后重定向** - 支持登录后返回原访问页面 + +#### 🎨 登录/注册页面 UI 升级 +- 采用 **Neumorphism(新拟态)** 设计风格 +- 健康主题配色(青色 + 绿色渐变) +- Lora + Raleway 字体组合 +- 柔和阴影效果,提升视觉体验 + +### 历史版本 + +- **2026-01-20** - 阅读模块上线(书库、心情追踪、统计图表) +- **2026-01-19** - 设置页面重构(用户档案、数据管理) +- **2026-01-17** - 公网部署支持(JWT 认证、邀请码、管理员面板) +- **2026-01-15** - 第一版发布(核心健康追踪功能) + ## License MIT diff --git a/src/vitals/core/__pycache__/auth.cpython-313.pyc b/src/vitals/core/__pycache__/auth.cpython-313.pyc index ef9ba84966b36c6d25ac6d600912c289d0590436..a3624dfb4fbbad3d00585cca0f9e61289e38310f 100644 GIT binary patch delta 1539 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�TZQ9eELmL?7OAb@Br% z3)@f4(&jY=w0;+BoU>J?++4wT|-k*mT{AGWo?7I%oT0 zu8U^FgU!Z|p+X3rg0-+ms3SHql&(9%eIjnFs#(>(->#Ec$(=x`XdCO7ay;LmZ$sdW z>f#-TE^cl8{O;>7?m2eh*sbbeRT*w4;PeEq<=bcSp{V>wd0msP|9q6f4Y2co_ssA< zpt8nFF9hgaE}W5?Ll_O2c+WpC^9RiA}gEb!%7y~P3tWxqnx zMrlo0algR@Mewh8V@KT77Lu^SS-9)p1Mj`Ex)izm+pjsf|qSoRyYfTk9*x; zf7;1Z4iN(%QX@rzn*z_wYAW!}xSc0sO=#olN^3pfICQ7$f6UP}HNjC4`Avs+es~5} z;a(K}GabAGL?4&hc^6F);4`t3-UWl68lHt98$k|&?f{f9;=+S9dHZTzqQvv$zpU2f zq>V(1Byf`YnzF8@va;6J4Bs8g;cIjSPV7S^+;yn}{#z{dGPVtw=>3HQOLWVB6P9jA za6f{>2#z73gNrw?bP2%^2}wiv+>1j7+nP+kd?6kTHjocZBrr}XV3r?b6j_&68AA_R*O*f1t-SlW)v_{kT? z6DIn)iM~(bt@yZ!IRS3L;x+`^5eNjk5j=?C00R6XgT9?m-!;62kG~+G3!8WaPQ6Ul z6HECB@LCDSJ0Bdc5paC3&hd3O$CtzOo|fKDIejkA;+qJ1d7vJ?)1fq-57Rj=9kb%u zp?X3`hh%hWfu}t%{F@x=xe6YAa6Fr!&Aqzkrqw;o+%$*KWI(C?R`MR@T}q&o2`Qyf z3Zij}15EwOpHkH*^eCMN0v)e4wd#Pg8MT)9+(V z>06r8^P1itYYNY6k}qhoKi16uKr{ax&HRrw)$eJl<-f1hRZ8E+w_Dfg3R$GY;gvOY?&M`{0~EU^?(2X diff --git a/src/vitals/web/app.py b/src/vitals/web/app.py index d73307a..b5b268f 100644 --- a/src/vitals/web/app.py +++ b/src/vitals/web/app.py @@ -7174,6 +7174,11 @@ def get_settings_page_html() -> str: + + + @@ -7631,12 +7636,37 @@ def get_settings_page_html() -> str: document.getElementById('account-role').textContent = user.is_admin ? '管理员账户' : '普通用户'; if (user.is_admin) { document.getElementById('account-badge').style.display = 'block'; + // 显示管理后台入口 + document.getElementById('admin-entry').style.display = 'block'; } // 保存到 localStorage localStorage.setItem('user', JSON.stringify(user)); + } else { + // 如果获取失败,尝试从 localStorage 获取 + const cachedUser = localStorage.getItem('user'); + if (cachedUser) { + const user = JSON.parse(cachedUser); + document.getElementById('account-name').textContent = user.name; + document.getElementById('account-role').textContent = user.is_admin ? '管理员账户' : '普通用户'; + if (user.is_admin) { + document.getElementById('account-badge').style.display = 'block'; + document.getElementById('admin-entry').style.display = 'block'; + } + } } } catch (error) { console.error('加载账户信息失败:', error); + // 尝试从 localStorage 获取 + const cachedUser = localStorage.getItem('user'); + if (cachedUser) { + const user = JSON.parse(cachedUser); + document.getElementById('account-name').textContent = user.name; + document.getElementById('account-role').textContent = user.is_admin ? '管理员账户' : '普通用户'; + if (user.is_admin) { + document.getElementById('account-badge').style.display = 'block'; + document.getElementById('admin-entry').style.display = 'block'; + } + } } }