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.
 

6.0 KiB

用户登录体系重构方案

创建时间:2025-01-14
状态:已完成


变更概述

将用户登录体系从传统的邮箱/密码登录重构为手机号验证码登录和微信扫码登录,支持多种账号绑定方式。


核心变更

1. 数据库层

users 表新增字段

-- 手机号相关
phone TEXT,
country_code TEXT DEFAULT '+86',
phone_verified BOOLEAN DEFAULT false,

-- 微信相关
wechat_openid TEXT,
wechat_unionid TEXT,
wechat_platform TEXT CHECK (wechat_platform IN ('mp', 'open')),

-- 用户名管理
username_changed BOOLEAN DEFAULT false,

-- 原有字段调整
email TEXT,  -- 移除 NOT NULL
password_hash TEXT,  -- 移除 NOT NULL

新增 sms_verification_codes 表

CREATE TABLE sms_verification_codes (
    code_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    phone TEXT NOT NULL,
    country_code TEXT NOT NULL DEFAULT '+86',
    code TEXT NOT NULL,
    purpose TEXT NOT NULL CHECK (purpose IN ('login', 'bind_phone')),
    expires_at TIMESTAMPTZ NOT NULL,
    verified BOOLEAN DEFAULT false,
    ip_address INET,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

2. 服务层

新增 SmsService

职责:短信验证码发送和验证

核心方法

  • send_verification_code() - 发送验证码
  • verify_code() - 验证验证码
  • clean_expired_codes() - 清理过期验证码

防刷策略

  • IP 限流:1分钟内最多 3 次
  • 手机号限流:1分钟内最多 1 次,1小时内最多 5 次
  • 验证码有效期:10 分钟

新增 WechatService

职责:微信登录和账号绑定

核心方法

  • generate_qrcode() - 生成微信登录二维码
  • handle_callback() - 处理微信回调
  • get_login_result() - 前端轮询获取登录结果
  • bind_wechat() - 绑定微信账号

支持平台

  • mp:微信公众号
  • open:微信开放平台

重构 UserService

新增方法

  • login_with_phone() - 手机号验证码登录
  • login_with_wechat() - 微信扫码登录
  • bind_phone() - 绑定手机号
  • bind_wechat() - 绑定微信
  • bind_email() - 绑定邮箱
  • update_username() - 修改用户名(仅一次)
  • generate_username() - 自动生成用户名

移除方法

  • register() - 不再需要显式注册

3. API 层

新增接口

POST   /api/v1/auth/sms/send              # 发送验证码
POST   /api/v1/auth/login/phone           # 手机号登录
GET    /api/v1/auth/wechat/qrcode         # 获取微信登录二维码
GET    /api/v1/auth/wechat/result         # 轮询登录结果
POST   /api/v1/users/me/bind/phone        # 绑定手机号
POST   /api/v1/users/me/bind/wechat       # 绑定微信
POST   /api/v1/users/me/bind/email        # 绑定邮箱
PUT    /api/v1/users/me/username          # 修改用户名

移除接口

POST   /api/v1/auth/register              # 不再需要显式注册
POST   /api/v1/auth/login                 # 邮箱/密码登录(后期可选支持)
POST   /api/v1/users/me/change-password   # 密码修改(后期可选支持)

技术实现

用户名自动生成

import time
import random
import string

def generate_username():
    timestamp = int(time.time())
    random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=4))
    return f"user_{timestamp}_{random_suffix}"

# 示例:user_1738012345_a3f9

验证码防刷

使用 Redis 实现分布式限流:

# IP 限流(1分钟内最多 3 次)
ip_key = f"sms:ip:{ip_address}"
ip_count = redis.get(ip_key)
if ip_count and int(ip_count) >= 3:
    raise RateLimitError("发送过于频繁")
redis.incr(ip_key)
redis.expire(ip_key, 60)

# 手机号限流(1分钟内最多 1 次)
phone_key_1min = f"sms:phone:{country_code}:{phone}:1min"
if redis.get(phone_key_1min):
    raise RateLimitError("验证码已发送")
redis.set(phone_key_1min, 1, ex=60)

# 手机号限流(1小时内最多 5 次)
phone_key_1hour = f"sms:phone:{country_code}:{phone}:1hour"
count = redis.incr(phone_key_1hour)
if count == 1:
    redis.expire(phone_key_1hour, 3600)
if count > 5:
    raise RateLimitError("今日发送次数已达上限")

微信登录流程

1. 前端请求二维码
   GET /api/v1/auth/wechat/qrcode?platform=mp

2. 后端生成 scene_id,返回二维码 URL

3. 用户扫码授权

4. 微信回调后端
   GET /api/v1/auth/wechat/callback?code=xxx&state=scene_id

5. 后端获取用户信息,存入 Redis

6. 前端轮询获取登录结果
   GET /api/v1/auth/wechat/result?scene_id=xxx

7. 返回 JWT Token

环境变量配置

# 短信服务(阿里云)
SMS_ACCESS_KEY_ID=your_access_key_id
SMS_ACCESS_KEY_SECRET=your_access_key_secret
SMS_SIGN_NAME=道研组
SMS_TEMPLATE_CODE=SMS_123456789

# 微信公众号
WECHAT_MP_APPID=wx1234567890abcdef
WECHAT_MP_SECRET=your_mp_secret
WECHAT_MP_CALLBACK_URL=https://api.jointo.ai/api/v1/auth/wechat/callback

# 微信开放平台
WECHAT_OPEN_APPID=wx0987654321fedcba
WECHAT_OPEN_SECRET=your_open_secret
WECHAT_OPEN_CALLBACK_URL=https://api.jointo.ai/api/v1/auth/wechat/callback

# Redis
REDIS_URL=redis://localhost:6379/0

依赖安装

# 短信服务
aliyun-python-sdk-core==2.13.36
aliyun-python-sdk-dysmsapi==3.0.0

# 微信 SDK
wechatpy==1.8.18

# Redis
redis==4.5.1

文档输出

创建的文档

  1. docs/需求/backend/04-services/sms-service.md - 短信验证码服务文档
  2. docs/需求/backend/04-services/wechat-service.md - 微信登录服务文档
  3. docs/计划/用户登录体系重构.md - 执行计划文档
  4. docs/方案/用户登录体系重构.md - 本方案文档

修改的文档

  1. docs/需求/backend/04-services/user-service.md - 用户管理服务文档(v2.0)

后续优化

  1. 支持邮箱验证码登录
  2. 支持 Google/Apple 第三方登录
  3. 支持国际短信(多国区号)
  4. 验证码图形验证码(防机器人)
  5. 微信小程序登录支持

文档版本:v1.0
创建时间:2025-01-14