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 ef9ba84..a3624df 100644
Binary files a/src/vitals/core/__pycache__/auth.cpython-313.pyc and b/src/vitals/core/__pycache__/auth.cpython-313.pyc differ
diff --git a/src/vitals/web/__pycache__/app.cpython-313.pyc b/src/vitals/web/__pycache__/app.cpython-313.pyc
index f483c3d..58135b6 100644
Binary files a/src/vitals/web/__pycache__/app.cpython-313.pyc and b/src/vitals/web/__pycache__/app.cpython-313.pyc differ
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';
+ }
+ }
}
}