# 账号状态实时响应技术方案 ## 背景需求 当管理员对用户账号进行冻结/封禁操作时,需要立即将当前在线用户的登录状态强制退出,保障平台安全。 --- ## 方案一: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过期时间一致 ```