diff --git a/docs/project_context.md b/docs/project_context.md index 4bb1694..6eb452c 100644 --- a/docs/project_context.md +++ b/docs/project_context.md @@ -2,6 +2,16 @@ ## 最近更新记录 +### 2026-04-23: 鉴权改为全屏登录页模式 + 退出登录 +- **问题**: 之前的鉴权方案只在 API 层拦截 401 后弹出登录弹窗,但主页面 HTML 内容已经完整渲染并暴露给用户(未登录也能看到界面),不符合安全预期。 +- **修复方案**: + - **登录页独立化**: 将登录从弹窗模式(`loginModal`)改为独立全屏登录页面(`#loginPage`),未登录时主内容区 `#appContainer` 设为 `display:none`,只显示登录页。 + - **Token 启动校验**: `DOMContentLoaded` 时先检查 `localStorage` 中的 token,无 token 直接显示登录页;有 token 则用 `/api/config` 接口验证有效性,401 则跳回登录页。 + - **退出登录功能**: 每个页面 header 右上角新增退出按钮(`⏻` 图标,`.logout-btn` 类),事件委托统一处理,清除 token 后显示登录页。 + - **登录后免刷新**: 登录成功后如果应用模块未初始化则调用 `initApp()` 完成初始化,无需 `window.location.reload()`。 +- **涉及文件**: `static/index.html`、`static/js/app.js`、`static/css/style.css` +- **注意事项**: `showLoginModal()` 函数保留作为兼容入口(API 返回 401 时调用),内部已重定向到 `showLoginPage()`。 + ### 2026-04-22: 增加 JWT 鉴权和接口安全控制 - **问题背景**: 网管部门通报安全问题,扫描到项目存在暴露的 API 文档(/docs, /redoc, /openapi.json),并且 API 接口没有使用授权控制,要求快速增加鉴权。 - **架构变更**: diff --git a/static/css/style.css b/static/css/style.css index bc4f84f..7f2ce1d 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -123,6 +123,102 @@ body { transition: background-color var(--td-transition), color var(--td-transition); } +/* ==================== 登录页面 ==================== */ +.login-page { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background: var(--td-bg-color-page); + z-index: 10001; +} + +.login-container { + width: 380px; + padding: 48px 40px; + background: var(--td-bg-color-container); + border-radius: var(--td-radius-large); + box-shadow: var(--td-shadow-3); + text-align: center; +} + +.login-logo { + font-size: 56px; + margin-bottom: 8px; + line-height: 1; +} + +.login-title { + font-size: 22px; + font-weight: 700; + color: var(--td-text-color-primary); + margin-bottom: 4px; + letter-spacing: 0.5px; +} + +.login-subtitle { + font-size: 14px; + color: var(--td-text-color-secondary); + margin-bottom: 32px; +} + +.login-form { + text-align: left; +} + +.login-form .form-group label { + display: block; + margin-bottom: 6px; + font-size: 13px; + font-weight: 500; + color: var(--td-text-color-primary); +} + +.login-form .form-input { + width: 100%; + height: 40px; + padding: 0 12px; + border: 1px solid var(--td-border-color); + border-radius: var(--td-radius-default); + font-size: 14px; + color: var(--td-text-color-primary); + background: var(--td-bg-color-container); + transition: all var(--td-transition); +} + +.login-form .form-input:focus { + outline: none; + border-color: var(--td-brand-color); + box-shadow: 0 0 0 2px var(--td-brand-color-focus); +} + +/* ==================== 退出登录按钮 ==================== */ +.logout-btn { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--td-border-color); + background: var(--td-bg-color-container); + color: var(--td-text-color-secondary); + border-radius: var(--td-radius-default); + cursor: pointer; + font-size: 16px; + transition: all var(--td-transition); + flex-shrink: 0; +} + +.logout-btn:hover { + border-color: var(--td-error-color); + color: var(--td-error-color); + background: var(--td-error-color-light); +} + /* 滚动条 */ ::-webkit-scrollbar { width: 8px; diff --git a/static/index.html b/static/index.html index e28c4ac..0b85f35 100644 --- a/static/index.html +++ b/static/index.html @@ -12,7 +12,27 @@ -
+ +
+ +
+ +
@@ -217,6 +239,7 @@ +
@@ -316,6 +339,7 @@ +
@@ -381,6 +405,7 @@ +
@@ -490,25 +515,7 @@
- - +