feat(auth): 实现登录限流和性能优化

性能优化:
- 添加数据库索引优化查询性能 (006)
  - weather_data: user_id, date, is_favorite 索引
  - users: openid 索引
  - payment_orders: status 索引
- 新增 refresh_tokens 表支持双 Token 机制 (004)
- 新增 web_login_codes 表支持网页端扫码登录 (005)

安全增强:
- 实现基于 IP 的登录限流 (rate_limiter.rs)
  - 滑动窗口算法: 5次/分钟/IP
  - 自动清理过期记录
  - 429 TooManyRequests 响应

新模块:
- src/rate_limiter.rs: 限流模块
- src/alipay.rs: 支付宝签名模块 (RSA2)
- src/error.rs: 统一错误类型 (含 TooManyRequests)
- src/handlers/meta.rs: 元数据处理器

代码清理:
- 修复 .gitignore 规则,正确跟踪 src/ 和 migrations/
This commit is contained in:
2026-04-24 16:13:49 +08:00
parent b3dc966576
commit e6048ea010
11 changed files with 852 additions and 9 deletions

View File

@@ -0,0 +1,27 @@
-- ============================================
-- 迁移: 004_add_refresh_tokens.sql
-- 目的: 添加 refresh_tokens 表支持双 Token 机制
-- 日期: 2026-04-18
-- 依赖: 无users 表已在 001 创建)
-- 说明: 用于存储 refresh_token支持 access_token 过期后自动续期
-- ============================================
-- 迁移: 添加 refresh_tokens 表
-- 用于支持 access_token 刷新机制
CREATE TABLE IF NOT EXISTS refresh_tokens (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token VARCHAR(512) NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 索引:加速 token 查询和用户清理
CREATE INDEX IF NOT EXISTS idx_refresh_tokens_token ON refresh_tokens(token);
CREATE INDEX IF NOT EXISTS idx_refresh_tokens_user_id ON refresh_tokens(user_id);
CREATE INDEX IF NOT EXISTS idx_refresh_tokens_expires_at ON refresh_tokens(expires_at);
COMMENT ON TABLE refresh_tokens IS 'Refresh token 存储表,支持 access_token 续期';
COMMENT ON COLUMN refresh_tokens.token IS 'Refresh token 字符串';
COMMENT ON COLUMN refresh_tokens.expires_at IS '过期时间';

View File

@@ -0,0 +1,27 @@
-- ============================================
-- 迁移: 005_add_web_login_codes.sql
-- 目的: 添加网页端微信扫码登录临时码表
-- 日期: 2026-04-20
-- 依赖: users 表001 创建)
-- 说明: 用户扫码后生成临时登录码,前端轮询验证登录状态
-- ============================================
-- 05_add_web_login_codes.sql
-- 网页端微信扫码登录:临时登录码表
CREATE TABLE IF NOT EXISTS web_login_codes (
id SERIAL PRIMARY KEY,
code VARCHAR(32) UNIQUE NOT NULL, -- 登录码,如 ASD-ABC123
user_id INTEGER, -- 关联用户(确认登录后写入)
openid VARCHAR(128), -- 用户 openid
token TEXT, -- 生成的 JWT确认后写入
expires_at TIMESTAMPTZ NOT NULL, -- 过期时间10分钟内有效
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 登录码索引
CREATE INDEX IF NOT EXISTS idx_web_login_codes_code ON web_login_codes(code);
CREATE INDEX IF NOT EXISTS idx_web_login_codes_expires ON web_login_codes(expires_at);
-- 定期清理过期登录码(可由 cron 或服务启动时触发)
-- DELETE FROM web_login_codes WHERE expires_at < NOW();

View File

@@ -0,0 +1,50 @@
-- 迁移: 006_add_performance_indexes.sql
-- 目的: 为常用查询字段添加索引,提升查询性能
-- 日期: 2026-04-24
-- ============================================
-- weather_data 表索引
-- ============================================
-- 索引:加速按用户查询天气数据列表
-- 用途GET /weather 接口按 user_id + date 排序查询
CREATE INDEX IF NOT EXISTS idx_weather_data_user_id ON weather_data(user_id);
-- 索引:加速按日期排序查询
-- 用途:列表查询默认按 date DESC, hour DESC, min DESC 排序
CREATE INDEX IF NOT EXISTS idx_weather_data_date ON weather_data(date DESC);
-- 索引:加速用户收藏列表查询
-- 用途GET /api/favorites 查询 user_id + is_favorite = true
CREATE INDEX IF NOT EXISTS idx_weather_data_user_favorite ON weather_data(user_id, is_favorite);
-- 索引:复合索引加速用户数据列表(无需额外排序)
-- 用途:用户历史记录查询
CREATE INDEX IF NOT EXISTS idx_weather_data_user_date ON weather_data(user_id, date DESC);
-- ============================================
-- users 表索引
-- ============================================
-- 索引:加速 openid 查询(登录时高频使用)
-- 注意openid 可能已有 UNIQUE 约束自动创建索引,此处确保存在
CREATE INDEX IF NOT EXISTS idx_users_openid ON users(openid);
-- ============================================
-- payment_orders 表索引(补充)
-- ============================================
-- 索引:加速按状态查询待处理订单
-- 用途:管理员查询 pending 状态订单
CREATE INDEX IF NOT EXISTS idx_payment_orders_status ON payment_orders(status);
-- ============================================
-- web_login_codes 表索引(来自 005
-- ============================================
-- 确保 web_login_codes 表索引存在05已创建此处确保兼容性
-- 登录码查询和过期清理
CREATE INDEX IF NOT EXISTS idx_web_login_codes_code ON web_login_codes(code);
CREATE INDEX IF NOT EXISTS idx_web_login_codes_expires_at ON web_login_codes(expires_at);
COMMENT ON TABLE weather_data IS '添加性能索引user_id、date、is_favorite';