You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.6 KiB
5.6 KiB
登录注册系统设计
日期: 2026/05/22 状态: 已批准,待实现
1. 核心架构:Strategy 模式
AuthService (统一入口)
├── PasswordStrategy ← 现在实现
└── OAuthStrategy ← 接口预留,以后实现 Google/GitHub 等
AuthService持有所有 Strategy 实例,通过type参数选择使用哪个 StrategyIAuthStrategy接口定义authenticate()和generateTokens()- 以后加 OAuth 只新增
GoogleStrategy extends OAuthStrategy,AuthService无需改动
2. 数据表扩展
users 表扩展字段
| 字段 | 类型 | 说明 |
|---|---|---|
email |
text | unique,加索引 |
emailVerified |
integer (bool) | 邮箱是否验证 |
passwordHistory |
text (JSON) | 最近 5 个密码 hash,防复用 |
failedLoginAttempts |
integer | 连续失败次数 |
lockoutUntil |
integer (timestamp) | 锁定截止时间 |
lastLoginAt |
integer (timestamp) | 最后登录时间 |
lastLoginIp |
text | 最后登录 IP |
refreshToken |
text | 当前 refresh token hash(兼容旧字段) |
user_sessions 表(新建)
| 字段 | 类型 | 说明 |
|---|---|---|
id |
text | session id (uuid) |
userId |
integer | 外键 references users.id |
refreshTokenHash |
text | token hash(bcrypt) |
userAgent |
text | 浏览器 UA |
ip |
text | 登录 IP |
createdAt |
integer (timestamp_ms) | 创建时间 |
expiresAt |
integer (timestamp_ms) | 过期时间 |
revokedAt |
integer (timestamp_ms) | 撤销时间,nullable |
3. 安全机制
密码
- bcrypt 加密,cost factor 12
- 注册:密码强度校验(8位以上,大小写+数字+特殊字符)
- 登录失败 5 次锁定 15 分钟
- 密码历史:最近 5 个密码不允许复用
Token
- Access Token:JWT,15 分钟有效期,payload 含 userId + sessionId + role
- Refresh Token:UUIDv4,7 天有效期,存储 hash 到 user_sessions
- Refresh Token 放 HTTP Only + Secure + SameSite=Strict Cookie
- Refresh Token Rotation:每次 refresh 颁发新 token,旧 token 作废
登录安全
- 记录 lastLoginAt / lastLoginIp
- 失败次数累计 + 锁定机制
- 通用限流:同一 IP 1 分钟内最多 5 次登录尝试(所有 auth 路由共享)
4. API 路由
POST /api/auth/register 注册
POST /api/auth/login 登录
POST /api/auth/logout 登出
POST /api/auth/refresh 刷新 token
GET /api/auth/me 获取当前用户
请求响应格式
POST /api/auth/register
// Request
{ "email": "user@example.com", "password": "Str0ng!", "username": "john" }
// Response 201
{ "user": { "id": 1, "email": "user@example.com", "username": "john" } }
POST /api/auth/login
// Request
{ "email": "user@example.com", "password": "Str0ng!" }
// Response 200
{
"user": { "id": 1, "email": "...", "username": "john", "role": "user" },
"accessToken": "<jwt>"
}
// RefreshToken 放 HTTP Only Cookie
POST /api/auth/logout
// Response 200
{ "success": true }
POST /api/auth/refresh
// Response 200(Cookie 自动发送)
{ "accessToken": "<new-jwt>" }
GET /api/auth/me
// Response 200
{ "user": { "id": 1, "email": "...", "username": "john", "role": "user" } }
错误响应格式
{ "error": { "code": "INVALID_CREDENTIALS", "message": "邮箱或密码错误" } }
错误码:
INVALID_CREDENTIALS— 登录失败ACCOUNT_LOCKED— 账户锁定WEAK_PASSWORD— 密码强度不足EMAIL_EXISTS— 邮箱已注册TOKEN_EXPIRED— access token 过期SESSION_REVOKED— session 已撤销
5. 目录结构
server/
├── api/auth/
│ ├── register.post.ts
│ ├── login.post.ts
│ ├── logout.post.ts
│ ├── refresh.post.ts
│ └── me.get.ts
├── service/auth/
│ ├── index.ts ← AuthService
│ ├── strategies/
│ │ ├── index.ts ← StrategyRegistry
│ │ ├── password.strategy.ts
│ │ └── oauth.strategy.ts ← 抽象类预留
│ └── lib/
│ ├── jwt.ts
│ ├── password.ts
│ └── rate-limit.ts
├── middleware/
│ └── auth.ts ← 请求认证中间件
└── types/
└── auth.ts
6. OAuth2 预留接口
interface IAuthStrategy {
readonly type: 'password' | 'oauth';
authenticate(credentials: unknown): Promise<User>;
generateTokens(user: User, sessionId: string): TokenPair;
revokeSession(sessionId: string): Promise<void>;
}
abstract class OAuthStrategy implements IAuthStrategy {
abstract readonly provider: 'google' | 'github' | string;
abstract readonly type: 'oauth';
abstract authenticate(oauthToken: string): Promise<User>;
generateTokens(user: User, sessionId: string): TokenPair { /* ... */ }
revokeSession(sessionId: string): Promise<void> { /* ... */ }
}
以后实现 OAuth 时:
- 新增
GoogleStrategy extends OAuthStrategy - 在
StrategyRegistry注册google: new GoogleStrategy() AuthService无需改动
7. 实现顺序
- Schema 迁移(users 字段扩展 + user_sessions 表)
PasswordStrategy实现(密码加密、校验、历史)AuthService+ Strategy 模式- API 路由(注册、登录、登出、刷新、获取用户)
- 中间件 + JWT 验证
- 限流 + 锁定机制
- 测试覆盖
8. 依赖组件(已有)
- bcryptjs — 密码加密
- Zod — 输入校验
- drizzle-orm — 数据库 ORM
- @libsql/client — SQLite 客户端