diff --git a/docs/账号状态实时响应技术方案.md b/docs/账号状态实时响应技术方案.md new file mode 100644 index 0000000..dbb7483 --- /dev/null +++ b/docs/账号状态实时响应技术方案.md @@ -0,0 +1,162 @@ +# 账号状态实时响应技术方案 + +## 背景需求 + +当管理员对用户账号进行冻结/封禁操作时,需要立即将当前在线用户的登录状态强制退出,保障平台安全。 + +--- + +## 方案一:WebSocket 实时推送 + +### 核心原理 + +服务端与客户端建立 TCP 长连接,当账号状态发生变化时,服务端主动通过 WebSocket 通道推送踢人指令,客户端收到后立即跳转登录页。 + +### 核心技术点 + +| 技术点 | 说明 | +|--------|------| +| **连接管理** | 服务端维护所有在线用户的 WebSocket 连接,使用 Map 管理 | +| **心跳机制** | 客户端每 30s 发送心跳,服务端检测存活,断线时移除连接 | +| **断线重连** | 客户端检测到断连后,采用指数退避策略重连(1s、2s、4s...最大 30s) | +| **消息协议** | 推送消息格式 `{type: "KICK_OUT", reason: "账号已被封禁", timestamp: 123456789}` | +| **多端同步** | 一个用户可能在手机、平板多端登录,需同时向所有连接推送 | + +### 流程图 + +``` +管理员操作 → 更新账号状态 → 消息队列 → WebSocket服务 → 推送至所有在线连接 → 客户端跳转登录页 +``` + +### 优缺点 + +- ✅ 实时性最强(毫秒级) +- ✅ 支持主动推送,可扩展系统通知等场景 +- ❌ 需要维护长连接池,增加运维复杂度 +- ❌ 移动端电量消耗较高 +- ❌ 弱网络环境下可能延迟不稳定 + +--- + +## 方案二:轮询检测 + +### 核心原理 + +客户端定期(如每 60 秒)调用账号状态查询接口,服务端返回当前账号状态,客户端根据返回值决定是否踢出用户。 + +### 核心技术点 + +| 技术点 | 说明 | +|--------|------| +| **轮询间隔** | 建议 60 秒,平衡实时性与服务器压力 | +| **请求优化** | 使用 `Last-Modified` / `ETag` 协商缓存,无变化时服务端返回 304 | +| **静默检测** | 检测在后台静默进行,不阻塞用户操作,不打断交互 | +| **差异化策略** | 新用户/高风险用户缩短轮询间隔,老用户/低风险用户延长间隔 | +| **错误处理** | 网络异常时继续轮询,不因单次失败终止 | + +### 流程图 + +``` +客户端定时器(60s) → 查询账号状态API → 返回status → + ├─ status == "normal" → 继续使用 + └─ status == "frozen/banned" → 跳转登录页 + 显示原因 +``` + +### 优缺点 + +- ✅ 实现简单,无需额外基础设施 +- ✅ 可复用现有接口,改动小 +- ✅ 调试方便,日志清晰 +- ❌ 存在延迟,最多等待一个轮询周期 +- ❌ 大规模用户时请求量较高 +- ❌ 客户端电量消耗 + +--- + +## 方案三:JWT Token 黑名单 + +### 核心原理 + +当账号被封禁时,将该用户的 Token 加入黑名单,后续每次请求网关校验 Token 时检查黑名单,发现则返回 401 强制登出。 + +### 核心技术点 + +| 技术点 | 说明 | +|--------|------| +| **存储选型** | 使用 Redis Set 存储黑名单 Token,O(1) 查询效率 | +| **Key 设计** | `blacklist:{userID}` 或 `blacklist:{tokenSignature}` | +| **过期策略** | Token 本身有过期时间,黑名单设置相同 TTL,自动清理 | +| **网关校验** | 在 JWT 校验层增加黑名单检查逻辑,位于 Token 验证之后 | +| **性能优化** | 本地缓存热点用户黑名单,减少 Redis 请求 | +| **批量封禁** | 管理员操作后可批量写入黑名单,减少数据库操作 | + +### 流程图 + +``` +管理员封禁 → 写入Redis黑名单 → 用户请求 → + → 网关校验JWT → 检查黑名单 → + ├─ 不在黑名单 → 继续处理请求 + └─ 在黑名单 → 返回401 + 跳转登录页 +``` + +### 优缺点 + +- ✅ 无需客户端配合,服务端完全可控 +- ✅ 分布式友好,多实例共享黑名单 +- ✅ 安全性高,Token 失效立即生效 +- ❌ 无法主动通知用户"为什么被封" +- ❌ 需要引入 Redis 依赖 + +--- + +## 推荐方案:轮询 + JWT 黑名单组合 + +### 组合策略 + +| 场景 | 处理方式 | 实时性 | +|------|---------|--------| +| **登录时** | 检测账号状态,异常拒绝登录 | 即时 | +| **登录后静默检测** | 每 60 秒轮询账号状态 | ≤60秒 | +| **被封禁后** | Token 加入黑名单,下次请求时拦截 | 即时 | +| **Token 校验** | 网关层检查黑名单 | 即时 | + +### 为什么组合使用 + +1. **轮询**解决"不知道为什么被封"的问题,用户下次操作时能拿到具体原因 +2. **黑名单**解决"Token 仍然有效"的问题,被封用户即使不轮询,请求也会被拦截 +3. 两者互补,覆盖所有边界场景 + +### 延迟分析 + +| 操作 | 响应时间 | +|------|---------| +| 管理员封禁 → 请求被拦截 | < 1秒(下次请求) | +| 管理员封禁 → 前端感知 | < 60秒(轮询周期) | + +### 后续扩展 + +如平台后续需要更多实时通知(如系统公告、消息提醒),可在组合方案基础上引入 WebSocket,不会浪费已有投资。 + +--- + +## 附录:数据库表结构参考 + +```sql +-- 账号状态表 +CREATE TABLE user_account_status ( + id SERIAL PRIMARY KEY, + user_id BIGINT NOT NULL UNIQUE, + status VARCHAR(20) NOT NULL, -- normal/frozen/banned + reason TEXT, -- 冻结/封号原因 + frozen_until BIGINT, -- 冻结解封时间戳(毫秒) + operator_id BIGINT, -- 操作人ID + operated_at BIGINT, -- 操作时间 + created_at BIGINT NOT NULL, + updated_at BIGINT NOT NULL +); + +-- Redis 黑名单Key设计 +-- Key: blacklist:user:{userID} +-- Value: 1 +-- TTL: 与Token过期时间一致 +```