## 1. 数据模型与迁移 - [x] 1.1 Prisma:`User` 新增 `lockedAt`/`lockReason`(可空,snake_case 映射 `locked_at`/`lock_reason`) - [x] 1.2 Prisma:`RefreshToken` 新增 `sid`(uuid v7,可空,加索引) - [x] 1.3 生成并部署 migration(`prisma migrate` / `migrate diff` + `deploy`) ## 2. 认证核心(sid + 锁定判定) - [x] 2.1 `issue()` 增加 `sid` 参数并写入 access token 载荷;登录时生成新 sid,刷新时沿用旧 sid 并携带 `loginAt/ip/userAgent`、延长 `expireAt` - [x] 2.2 `loginTenant` 与 `refresh` 拒绝 `lockedAt != null` 的账号 - [x] 2.3 `checkUserActive` 的 user-state 缓存对象扩展为 `{status, tokenVersion, lockedAt}`,`!lockedAt` 才放行 - [x] 2.4 `JwtAuthGuard` 在 checkUserActive 后追加 sid 黑名单判定(Redis `sessionRevoked:{sid}`,命中即 401) ## 3. 在线会话模块 - [x] 3.1 新增 `sessions` 模块(service + controller + DTO) - [x] 3.2 `GET /sessions`:分页查询活跃会话(join user 取 username/nickname),按用户名/IP 筛选,按数据权限过滤可见用户 - [x] 3.3 `POST /sessions/:sid/kick`:吊销该 sid 的 refresh token + 写 Redis 黑名单(TTL=ACCESS_TTL) ## 4. 用户锁定/解锁与踢全部 - [x] 4.1 `users` service 新增 `lock`/`unlock`/`kickSessions` - [x] 4.2 `lock`:置 `lockedAt/lockReason` + 调 `invalidateSessions`;`unlock`:清锁定 + 清登录失败计数(loginFail key) - [x] 4.3 `users` controller 新增 `POST /users/:id/lock`、`POST /users/:id/unlock`、`POST /users/:id/kick-sessions` ## 5. 资源注册与存量补齐 - [x] 5.1 `Permissions` 枚举新增 `session:list`、`session:kick`、`user:kickSessions`、`user:lock`、`user:unlock` - [x] 5.2 `tenant-template` 新增 session 菜单(parent=monitor,/monitor/session)与上述接口资源 - [x] 5.3 提取 `syncTenantResources`(仅资源+字典+授权,不触碰用户/密码),提供存量租户补齐脚本并执行 ## 6. 前端 API - [x] 6.1 新增 `api/session.ts`:`listSessions`、`kickSession` - [x] 6.2 `api/user.ts` 扩展 `kickSessions`、`lockUser`、`unlockUser` ## 7. 前端页面 - [x] 7.1 新增 `pages/monitor/session/index.vue`:会话列表 + 单个强退 + 按用户踢全部(确认框) - [x] 7.2 `pages/system/user/index.vue`:新增「锁定/解锁」操作,锁定状态以标签展示 ## 8. 验证 - [x] 8.1 后端 build + 单测通过 - [x] 8.2 前端 type-check 通过 - [x] 8.3 冒烟测试:登录 → 锁定用户(旧 token 失效)→ 会话列表 → 单会话强退 → 解锁后恢复登录