6.16 在线用户监控
概述
在线用户是无表模块(数据源 Redis):登录/刷新登记会话,分页查看在线列表,强退踢出(access+refresh 双令牌拉黑,防被踢会话经刷新复活)。路由前缀 /api/onlineUser。
数据结构(Redis)
text
zset easygoadmin:online:jti:set score = 访问令牌过期时间戳
键 easygoadmin:online:info:{jti} JSON 详情(TTL = access 剩余期 + 60s)
onlineInfo 字段:
jti / userId / username / realname / ip / location / os / browser /
loginTime / issuedAt / expireAt / refreshJti / refreshIssuedAt / refreshExpireAt /
accessToken / refreshToken(令牌原文,仅详情查看返回)/ tokenType / expiresIn会话生命周期
text
登录/refresh 成功
│ MarkOnline
▼
┌─────────────────────────────────────────────┐
│ zset easygoadmin:online:jti:set │ score=access过期ts
│ 键 easygoadmin:online:info:{jti} = JSON │ TTL=access剩余+60s
└──────────────────┬──────────────────────────┘
页面访问(有效期内)│ │登出 Logout / 强退 ForceLogout
(token 有效,│ ▼ MarkOffline + access/refresh 双拉黑
JWT 放行) │ zset 移除 + info 删除 → 会话消失
▼
access 到期:zset score < now 被区间过滤(列表不可见);
info 键 TTL 到期自动清除
refresh 到期:无法再换新令牌
无心跳/续期机制:会话有效期即 access 令牌有效期(2h);
前端 refresh 轮换会刷新在线登记(MarkOnline 覆盖写)接口清单
| 方法 | 路由 | 权限 | 说明 |
|---|---|---|---|
| GET | /api/onlineUser/page | sys:onlineUser:page | 在线会话分页 |
| GET | /api/onlineUser/detail/:id | sys:onlineUser:detail | 会话详情(含令牌原文) |
| GET | /api/onlineUser/forceLogout/:id | sys:onlineUser:forceLogout | 单会话强退 |
| GET | /api/onlineUser/forceLogoutUser/:userId | sys:onlineUser:forceLogout | 踢出该用户全部设备 |
Page 流程
text
ZRangeByScore(now..+∞) → 逐 jti 读详情 → username/ip 子串过滤
→ 按登录时间倒序 → 同用户多会话标注(SessionNo/Sessions 序号与总数)
→ 批量回填头像(按 userId 查 user.avatar,GetFileUrl 补域名,单用户只查一次)
→ 内存分页(NewPageData)强退的双令牌拉黑(安全关键)
text
单会话强退(forceLogout/:id):
1) access jti 拉黑(TTL=剩余期+60s)
2) refresh jti 一并拉黑——防被踢会话经 refresh 换新令牌复活
3) MarkOffline(zset 移除 + info 删除)
踢全部设备(forceLogoutUser/:userId):
遍历 zset 匹配 userId → 逐会话双令牌拉黑 + 注销为什么双拉黑
只拉黑 access 的话,被踢用户的 refresh_token 仍能兑换新令牌对重新"复活"。access+refresh 一并拉黑才能真正踢出。
排障
| 症状 | 原因 |
|---|---|
| 在线列表为空但有人在线 | Redis 内存降级(各实例独立);或会话已过 access 有效期 |
| 强退后对方仍能请求 | 该实例内存降级(黑名单不跨实例);等窗口或查 /api/cache/info |
| 会话数偏多 | access 2h 有效期内多次登录=多会话(同用户多设备标注序号) |
| 详情泄露令牌原文 | 设计如此(运维排查用),依赖 sys:onlineUser:detail 权限收口 |