docs: 账户状态响应

This commit is contained in:
zerosaturation 2026-04-27 13:17:57 +08:00
parent 112d3907be
commit cf12f6e37e

View File

@ -0,0 +1,162 @@
# 账号状态实时响应技术方案
## 背景需求
当管理员对用户账号进行冻结/封禁操作时,需要立即将当前在线用户的登录状态强制退出,保障平台安全。
---
## 方案一WebSocket 实时推送
### 核心原理
服务端与客户端建立 TCP 长连接,当账号状态发生变化时,服务端主动通过 WebSocket 通道推送踢人指令,客户端收到后立即跳转登录页。
### 核心技术点
| 技术点 | 说明 |
|--------|------|
| **连接管理** | 服务端维护所有在线用户的 WebSocket 连接,使用 Map<userID, Connection> 管理 |
| **心跳机制** | 客户端每 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 存储黑名单 TokenO(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过期时间一致
```