Rocket.Chat 怎么禁用用户并处理解禁后需重新邀请的行为?
【免费下载链接】Rocket.ChatThe Secure CommsOS™ for mission-critical operations项目地址: https://gitcode.com/GitHub_Trending/ro/Rocket.Chat
在 Rocket.Chat 中,当你需要把某个用户踢出某个频道或群组、同时又不想丢失其订阅记录时,应该使用「封禁(Ban)」而不是「踢出(Kick)」。封禁会把该用户的订阅记录保留下来并标记为status: 'BANNED',形成一道持久的访问屏障;而踢出是直接删除订阅。本文覆盖完整的操作路径:执行封禁、查看被封禁用户列表、执行解禁,以及解禁之后为什么该用户必须被重新邀请或重新加入才能回到房间。
封禁前确认权限与适用条件
执行封禁的用户需要具备ban-user权限,默认拥有该权限的角色是admin、owner、moderator(权限按房间作用域校验)。服务端还会做以下检查(见 封禁校验逻辑):
- 该房间类型允许执行封禁操作(
roomDirectives.allowMemberAction); - 执行者本人对该房间有访问权限;
- 目标用户存在且当前在房间中,否则报
User not found或User is not in this room; - 目标用户已处于封禁状态时拒绝重复封禁(
User is already banned from this room); - 目标是房间内最后一个 owner 时拒绝,需先指定新的 owner(
You are the last owner. Please set new owner before banning the user.)。
确认以上条件后,封禁可以通过三种入口触发:UI、API、斜杠命令。
执行封禁
UI 路径:进入房间后,在用户信息面板中对目标用户执行封禁操作。该入口由ban-user权限、roomCanBan及 federation 规则共同控制。执行时会出现danger样式的确认弹窗(GenericModal)。
API 路径:调用POST /v1/rooms.banUser,需要认证(authRequired: true)。请求体支持两种形式(见 REST 类型定义):
{ "userId": "用户ID", "roomId": "房间ID" }或:
{ "username": "目标用户名", "roomId": "房间ID" }成功时返回{ "success": true }(端点实现见 rooms.ts)。
斜杠命令路径:在房间中输入/ban @username(实现位于 ban.ts)。
封禁执行后(核心逻辑见 封禁功能文档):
- 订阅被更新为
status: 'BANNED',记录本身不会被删除; - 该房间从用户的
__rooms数组中移除,房间的usersCount递减; - 频道和群组中的房间级角色(
moderator、owner、leader)被移除;如果该房间是团队主房间,成员还会从团队中移除; - 保存一条
user-banned系统消息; - 客户端收到订阅上的
removed事件,断开该房间的流。
查看被封禁用户列表
房间工具箱(room toolbox)中有Banned Users标签页,需要ban-user权限才能看到,列表支持虚拟滚动与无限分页。对应 API 为GET /v1/rooms.bannedUsers,需要认证且调用者必须能访问该房间,支持count与offset分页参数,返回结构包含bannedUsers(每项含_id、username、name)、count、offset、total。
执行解禁
解禁同样有三种入口:
- UI:在 Banned Users 列表项的上下文菜单中执行解禁(
danger确认弹窗); - API:
POST /v1/rooms.unbanUser,请求体格式与封禁一致(userId或username+roomId),成功返回{ "success": true }; - 斜杠命令:
/unban @username(见 unban.ts)。
解禁的服务端行为(解禁流程):
- 通过
findOneBannedSubscription找到被封禁的订阅; - 整条删除该订阅(
Subscriptions.removeById),而不是把它恢复为活跃状态; - 保存一条
user-unbanned系统消息。
解禁后用户必须重新入房
这是最容易踩坑的一点:解禁不会让用户重新成为房间成员。被封禁的订阅已经被删除,用户此刻对该房间没有任何有效订阅,处于“从未加入”的状态。因此解禁之后必须再走一次入房流程:
- 公开房间:用户自行加入即可;
- 私有房间或团队:由管理员通过 UI 的 “Add Users”、API(
groups.invite、channels.invite)或邀请链接重新邀请。
完整的预期流程是:先解禁(API、/unban @username或 “Banned Users” 上下文栏),删除被封禁的订阅;然后再邀请或加入,用户即可正常回到房间。
反过来,封禁期间该用户的任何入房路径都会被拦截:
- 邀请被拒:
addUsersToRoom在调用addUserToRoom之前先检查BANNED订阅,命中则返回error-user-is-banned,UI 会弹出警告提示管理员先解禁。该检查位于方法层,对普通房间和 federation 房间同样生效。 - 邀请链接失效:
useInviteToken在保存邀请 token 或调用addUserToRoom之前就检查BANNED订阅,命中则返回error-user-is-banned,token 不会被消费;经由setUsername的注册入房路径也因此被阻断。 - 直接加入被拒:
Room.join先调用canAccessRoom。公开房间与团队内的公开房间会显式检查findOneBannedSubscription并拒绝访问;私有房间则因countByRoomIdAndUserId排除了BANNED订阅,导致“已加入”校验为 false,访问被拒绝。 - Federation 邀请事件:Matrix 侧发送的邀请会被
handleInvite提前返回,不会产生新的INVITED订阅,因此也走不到handleJoin。
系统消息与参考
| 系统消息 | 触发时机 |
|---|---|
user-banned | 用户被从房间封禁 |
user-unbanned | 用户被解禁(包括经重新添加触发的解禁) |
REST 端点汇总:
| Method | Endpoint | 说明 |
|---|---|---|
| POST | /v1/rooms.banUser | 封禁用户(接受userId或username+roomId) |
| POST | /v1/rooms.unbanUser | 解禁用户 |
| GET | /v1/rooms.bannedUsers | 分页列出被封禁用户 |
相关实现文件:封禁校验、REST 端点、封禁/解禁斜杠命令、功能说明文档。
【免费下载链接】Rocket.ChatThe Secure CommsOS™ for mission-critical operations项目地址: https://gitcode.com/GitHub_Trending/ro/Rocket.Chat
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考