Files
teaching-design/docs/superpowers/specs/2026-06-15-auth-system-design.md

126 lines
3.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 用户账号系统设计
**日期:** 2026-06-15
**状态:** 已批准
## 背景
项目现状Vue 前端 + Hono/Bun 后端 + SQLite所有数据对任何人开放访问无任何认证。目标是加入登录门禁防止陌生人访问但所有登录用户共享同一份数据。
## 核心决策
- 多用户账号,存数据库,管理员创建账号(不开放注册)
- access tokenJWT15分钟+ 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**JWTHS256payload `{ 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` header401 时触发 refresh
### useAuth composable 行为
- localStorage 存 `access_token``refresh_token`
- 导出:`isLoggedIn`computed`user`ref`login()``logout()`
- 提供 `authedFetch()` 封装:自动带 token遇 401 先尝试 refreshrefresh 失败则清除 token 跳登录页
### AdminPage
- 仅当 `user.role === 'admin'` 时在主界面显示入口
- 功能:列出所有用户、创建账号(用户名+密码)、删除账号(不能删除自己)
---
## 四、环境变量
`.env` 新增:
```
JWT_SECRET=<随机长字符串>
ADMIN_USERNAME=admin
ADMIN_PASSWORD=<初始密码>
```
---
## 五、依赖
- `jsonwebtoken` 或 Hono 自带的 `hono/jwt` — JWT 操作
- `bcryptjs` — 密码 hash纯 JS兼容 Bun
---
## 六、不在本次范围内
- 修改密码功能
- 邮件验证
- 多 admin 角色权限细分