# 用户账号系统设计 **日期:** 2026-06-15 **状态:** 已批准 ## 背景 项目现状:Vue 前端 + Hono/Bun 后端 + SQLite,所有数据对任何人开放访问,无任何认证。目标是加入登录门禁,防止陌生人访问,但所有登录用户共享同一份数据。 ## 核心决策 - 多用户账号,存数据库,管理员创建账号(不开放注册) - access token(JWT,15分钟)+ refresh token(随机UUID入库,7天)双 token 方案 - refresh token hash 后存库,支持撤销 --- ## 一、数据库 Schema 在现有 `books` 表旁新增两张表,在 `server/db.ts` 的 `SCHEMA` 中追加: ```sql CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, username TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'user', created_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS refresh_tokens ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, token_hash TEXT NOT NULL, expires_at TEXT NOT NULL, created_at TEXT NOT NULL ); ``` **初始 admin 账号:** 服务启动时读取环境变量 `ADMIN_USERNAME` / `ADMIN_PASSWORD`,若 users 表中不存在该用户名则自动写入。密码用 bcrypt hash 存储。 --- ## 二、服务端 API ### 新增文件 - `server/auth.ts` — JWT 签发/验证、bcrypt、token CRUD 的纯函数 - `server/middleware/auth.ts` — Hono 中间件(验证 Bearer token,注入 user 到 context) - `server/routes/auth.ts` — `/api/auth/*` 路由 - `server/routes/admin.ts` — `/api/admin/*` 路由 ### 端点列表 | 方法 | 路径 | 说明 | 认证要求 | |------|------|------|----------| | POST | `/api/auth/login` | 登录,返回 access + refresh token | 无 | | POST | `/api/auth/refresh` | 换新 access token | 无(带 refresh token) | | POST | `/api/auth/logout` | 撤销当前 refresh token | Bearer | | GET | `/api/auth/me` | 返回当前用户信息 | Bearer | | GET | `/api/admin/users` | 列出所有用户 | Admin only | | POST | `/api/admin/users` | 创建新用户 | Admin only | | DELETE | `/api/admin/users/:id` | 删除用户 | Admin only | ### 现有路由保护 `/api/books/*` 和 `/api/generate/*` 全部加上 auth 中间件,未认证返回 401。 ### Token 规格 - **access token**:JWT,HS256,payload `{ userId, role, exp: now+15min }`,密钥来自环境变量 `JWT_SECRET` - **refresh token**:`crypto.randomUUID()`,SHA-256 hash 后存 `refresh_tokens` 表,原始值返回给客户端 --- ## 三、前端 ### 新增文件 - `src/composables/useAuth.ts` — token 管理、登录/登出/刷新逻辑 - `src/components/LoginPage.vue` — 登录表单 - `src/components/AdminPage.vue` — 用户管理页(admin 专属) ### 修改文件 - `src/App.vue` — 根据登录状态切换渲染 LoginPage 或主应用 - `src/services/booksApi.ts` — 所有请求加 `Authorization` header,401 时触发 refresh ### useAuth composable 行为 - localStorage 存 `access_token` 和 `refresh_token` - 导出:`isLoggedIn`(computed)、`user`(ref)、`login()`、`logout()` - 提供 `authedFetch()` 封装:自动带 token,遇 401 先尝试 refresh,refresh 失败则清除 token 跳登录页 ### AdminPage - 仅当 `user.role === 'admin'` 时在主界面显示入口 - 功能:列出所有用户、创建账号(用户名+密码)、删除账号(不能删除自己) --- ## 四、环境变量 `.env` 新增: ``` JWT_SECRET=<随机长字符串> ADMIN_USERNAME=admin ADMIN_PASSWORD=<初始密码> ``` --- ## 五、依赖 - `jsonwebtoken` 或 Hono 自带的 `hono/jwt` — JWT 操作 - `bcryptjs` — 密码 hash(纯 JS,兼容 Bun) --- ## 六、不在本次范围内 - 修改密码功能 - 邮件验证 - 多 admin 角色权限细分