群聊系统架构与业务设计
📋 概述
本文档全面解析OpenIM群聊系统的完整架构设计,涵盖存储架构、业务逻辑、权限控制和管理流程等核心模块:
🏗️ 系统架构层次
- 存储架构:客户端SQLite + 服务端MongoDB + Redis缓存的三层存储体系
- 业务架构:群组管理、成员管理、权限控制、申请审核等完整业务流程
- 权限架构:基于角色的分级权限控制体系,支持精细化权限管理
- 通知架构:实时通知机制,确保群组状态变更的及时同步
通过本文档,您将全面了解OpenIM群聊系统从底层存储到上层业务的完整设计架构。
第一部分:客户端存储层(SQLite)
🗄️ 核心表结构概览
OpenIM SDK 使用四个核心表实现完整的群聊数据存储:
表名 | 作用 | 数据特点 | 查询频率 |
---|---|---|---|
LocalGroup | 群组基础信息 | 相对稳定,变更较少 | 高频查询 |
LocalGroupMember | 群成员信息 | 动态变化,成员进出频繁 | 超高频查询 |
LocalGroupRequest | 群申请记录 | 临时数据,定期清理 | 中频查询 |
LocalChatLog | 群聊消息记录 | 数据量大,增长快速 | 超高频查询 |
📋 1. LocalGroup - 本地群组信息表
表名 : local_groups
完整字段结构
字段名 | 字段类型 | 索引 | 详细描述 |
---|---|---|---|
GroupID | string(64) [主键] | PRIMARY KEY | 群组唯一标识 • 全局唯一的群组ID • 与服务端保持一致 • 作为主键,关联群成员和消息表 |
GroupName | string(255) | 无 | 群组名称 • 群聊显示名称 • 支持实时更新 • 影响会话列表显示 |
Notification | string(255) | 无 | 群公告内容 • 群主/管理员发布的公告 • 支持富文本格式 • 客户端弹窗提醒 |
Introduction | string(255) | 无 | 群组介绍 • 群组详细描述 • 加群时展示给申请者 • 群信息页面显示 |
FaceURL | string(255) | 无 | 群头像URL • 群组头像地址 • 支持本地缓存 • 会话列表头像显示 |
CreateTime | int64 | 无 | 创建时间戳 • 群组创建时间 • 毫秒级时间戳 • 用于群组排序 |
Status | int32 | 无 | 群组状态枚举 • 0 = 正常状态 (GroupOk) • 1 = 群禁言状态 (GroupBanChat) • 2 = 群解散状态 (GroupStatusDismissed) • 3 = 群静音状态 (GroupStatusMuted) |
CreatorUserID | string(64) | 无 | 创建者用户ID • 群组创建者标识 • 与用户表关联 • 用于权限判断 |
GroupType | int32 | 无 | 群组类型枚举 • 0 = 普通群 (NormalGroup) • 1 = 超级群 (SuperGroup) • 2 = 工作群 (WorkingGroup) |
OwnerUserID | string(64) | 无 | 群主用户ID • 当前群主标识 • 支持转让变更 • 最高权限拥有者 |
MemberCount | int32 | 无 | 群成员数量 • 实时成员统计 • 避免实时count查询 • 上限根据群类型确定 |
Ex | string(1024) | 无 | 扩展字段 • 自定义数据存储 • JSON格式 • 业务扩展使用 |
AttachedInfo | string(1024) | 无 | 附加信息 • 额外业务数据 • 可选的元数据信息 • 客户端自定义使用 |
NeedVerification | int32 | 无 | 入群验证设置枚举 • 0 = 申请需要验证, 邀请直接进群 (ApplyNeedVerificationInviteDirectly) • 1 = 所有人需要验证,除了群主管理员邀请 (AllNeedVerification) • 2 = 直接进群 (Directly) |
LookMemberInfo | int32 | 无 | 查看成员信息权限枚举 • 0 = 所有人可查看 (ALL) • 1 = 仅群成员可查看 (MEMBER_ONLY) • 2 = 仅管理员可查看 (ADMIN_ONLY) • 3 = 禁止查看 (FORBIDDEN) |
ApplyMemberFriend | int32 | 无 | 添加成员为好友权限枚举 • 0 = 允许添加 (ALLOW) • 1 = 需要验证 (NEED_VERIFICATION) • 2 = 禁止添加 (FORBIDDEN) • 3 = 仅管理员可添加 (ADMIN_ONLY) |
NotificationUpdateTime | int64 | 无 | 群公告更新时间戳 • 公告最后更新时间 • 用于公告变更提醒 • 毫秒级时间戳 |
NotificationUserID | string(64) | 无 | 群公告更新者ID • 最后修改公告的用户 • 公告来源追踪 • 权限验证使用 |
👥 2. LocalGroupMember - 本地群成员信息表
表名 : local_group_members
完整字段结构
字段名 | 字段类型 | 索引 | 详细描述 |
---|---|---|---|
GroupID | string(64) [联合主键] | PRIMARY KEY | 群组标识 • 关联群组表 • 成员归属群组 • 联合主键组成部分 |
UserID | string(64) [联合主键] | PRIMARY KEY | 成员用户ID • 用户唯一标识 • 联合主键组成部分 • 一个用户在一个群中唯一 |
Nickname | string(255) | 无 | 群内昵称 • 成员在群内显示名称 • 可与真实昵称不同 • 群主/管理员可修改 |
FaceURL | string(255) | 无 | 成员头像URL • 用户头像快照 • 群内头像显示 • 支持本地缓存 |
RoleLevel | int32 | INDEX | 角色等级枚举 • 20 = 普通成员 (GroupOrdinaryUsers) • 60 = 管理员 (GroupAdmin) • 100 = 群主 (GroupOwner) • 权限递增,索引优化查询 |
JoinTime | int64 | INDEX | 加入时间戳 • 成员入群时间 • 毫秒级时间戳 • 成员列表排序依据 |
JoinSource | int32 | 无 | 加入来源枚举 • 1 = 管理员邀请 (JoinByAdmin) • 2 = 邀请加入 (JoinByInvitation) • 3 = 搜索加入 (JoinBySearch) • 4 = 扫码加入 (JoinByQRCode) |
InviterUserID | string(64) | 无 | 邀请者用户ID • 邀请该成员的用户 • 追踪邀请关系 • 入群来源管理 |
MuteEndTime | int64 | 无 | 禁言结束时间戳 • 0表示未被禁言 • 大于当前时间表示禁言中 • 毫秒级时间戳 |
OperatorUserID | string(64) | 无 | 操作者用户ID • 最后操作该成员的用户 • 用于操作日志记录 • 权限变更追踪 |
Ex | string(1024) | 无 | 扩展字段 • 成员自定义数据 • JSON格式存储 • 业务扩展使用 |
AttachedInfo | string(1024) | 无 | 附加信息 • 成员相关元数据 • 可选的业务信息 • 灵活扩展支持 |
📨 3. LocalGroupRequest - 本地群申请记录表
表名 : local_group_request
完整字段结构
字段名 | 字段类型 | 索引 | 详细描述 |
---|---|---|---|
GroupID | string(64) [联合主键] | PRIMARY KEY | 目标群组ID • 申请加入的群组 • 联合主键组成部分 |
UserID | string(64) [联合主键] | PRIMARY KEY | 申请者用户ID • 发起申请的用户 • 联合主键组成部分 |
GroupName | string(255) | 无 | 群组名称快照 • 申请时的群名 • 避免群名变更后显示异常 • 申请列表展示使用 |
Notification | string(255) | 无 | 群公告快照 • 申请时的群公告 • 申请页面展示 • 用户了解群组信息 |
Introduction | string(255) | 无 | 群介绍快照 • 申请时的群介绍 • 帮助用户了解群组 • 申请决策参考 |
GroupFaceURL | string(255) | 无 | 群头像快照 • 申请时的群头像 • 申请列表头像展示 • 保持视觉一致性 |
CreateTime | int64 | 无 | 群组创建时间 • 群组创建时间快照 • 群组基本信息 |
CreatorUserID | string(64) | 无 | 群创建者ID • 群组创建者快照 • 群组历史信息 |
GroupType | int32 | 无 | 群组类型快照 • 申请时的群类型 • 类型变更后的历史记录 |
OwnerUserID | string(64) | 无 | 群主ID快照 • 申请时的群主 • 群主变更后的历史记录 |
MemberCount | int32 | 无 | 成员数量快照 • 申请时的成员数 • 群规模参考信息 |
Nickname | string(255) | 无 | 申请者昵称 • 申请者当时昵称 • 审核时显示使用 • 历史昵称记录 |
UserFaceURL | string(255) | 无 | 申请者头像 • 申请者当时头像 • 审核页面头像展示 • 快照保持一致性 |
HandleResult | int32 | 无 | 处理结果枚举 • 0 = 待处理 (默认状态) • 1 = 同意 (GroupResponseAgree) • -1 = 拒绝 (GroupResponseRefuse) |
ReqMsg | string(255) | 无 | 申请消息 • 申请者填写的入群理由 • 帮助管理员决策 • 最大255字符 |
HandledMsg | string(255) | 无 | 处理消息 • 管理员处理时填写的消息 • 同意/拒绝的具体原因 • 反馈给申请者 |
ReqTime | int64 | 无 | 申请时间戳 • 申请发起时间 • 毫秒级时间戳 • 申请列表排序依据 |
HandleUserID | string(64) | 无 | 处理者用户ID • 处理申请的管理员/群主 • 权限追踪 • 操作日志记录 |
HandledTime | int64 | 无 | 处理时间戳 • 申请处理时间 • 0表示未处理 • 处理效率统计 |
Ex | string(1024) | 无 | 扩展字段 • 申请相关自定义数据 • JSON格式存储 |
AttachedInfo | string(1024) | 无 | 附加信息 • 申请相关元数据 • 业务扩展支持 |
JoinSource | int32 | 无 | 申请来源 • 与成员表JoinSource对应 • 申请渠道统计 |
InviterUserID | string(64) | 无 | 邀请者ID • 如通过邀请申请 • 邀请关系追踪 |
第二部分:服务端存储层
🏗️ 架构概览
服务端采用三层存储架构:
- MongoDB:持久化存储,保证数据安全和事务一致性
- Redis:高速缓存,提升查询性能,支持大群场景
🗄️ MongoDB 数据库存储层
1. Group - 群组核心表
集合名 : group
完整字段结构
字段名 | 字段类型 | 索引 | 详细描述 |
---|---|---|---|
_id | ObjectId | PRIMARY KEY | MongoDB主键 • 自动生成的唯一标识 |
GroupID | string | UNIQUE INDEX | 群组唯一标识 • 业务层面的唯一ID • 与客户端保持一致 • 关键查询索引字段 |
GroupName | string | 无 | 群组名称 • 群聊显示名称 • 支持修改更新 • 搜索功能使用 |
Notification | string | 无 | 群公告内容 • 富文本群公告 • 支持链接和格式 • 群管理功能核心 |
Introduction | string | 无 | 群组介绍 • 群组详细描述 • 搜索和推荐使用 • 入群申请展示 |
FaceURL | string | 无 | 群头像URL • 群组头像存储链接 • CDN分发优化 • 多端同步显示 |
CreateTime | time.Time | INDEX | 创建时间 • MongoDB时间类型 • 自动索引优化 • 统计分析使用 |
Ex | string | 无 | 扩展字段 • 业务自定义数据 • JSON格式存储 • 灵活扩展支持 |
Status | int32 | 无 | 群组状态 • 0 = 正常 (GroupOk) • 1 = 群禁言状态 (GroupBanChat) • 2 = 群解散状态 (GroupStatusDismissed) • 3 = 群静音状态 (GroupStatusMuted) |
CreatorUserID | string | 无 | 创建者用户ID • 群组创建者标识 • 历史记录保存 • 权限判断依据 |
GroupType | int32 | 无 | 群组类型 • 0 = 普通群 (NormalGroup) • 1 = 超级群 (SuperGroup) • 2 = 工作群 (WorkingGroup) • 不同类型不同规则 |
NeedVerification | int32 | 无 | 入群验证设置 • 控制入群门槛 • 群管理策略 • 自动化审核规则 |
LookMemberInfo | int32 | 无 | 查看成员权限 • 隐私保护设置 • 成员信息可见性 • 安全策略配置 |
ApplyMemberFriend | int32 | 无 | 加好友权限 • 群内社交控制 • 防骚扰机制 • 隐私保护策略 |
NotificationUpdateTime | time.Time | 无 | 公告更新时间 • 公告版本控制 • 变更通知依据 • 时间戳精确记录 |
NotificationUserID | string | 无 | 公告更新者 • 操作者追踪 • 管理审计日志 • 权限验证使用 |
2. GroupMember - 群成员表
集合名 : group_member
完整字段结构
字段名 | 字段类型 | 索引 | 详细描述 |
---|---|---|---|
_id | ObjectId | PRIMARY KEY | MongoDB主键 |
GroupID | string | INDEX | 群组ID • 复合索引:group_id + user_id • 成员归属群组 • 高频查询优化 |
UserID | string | INDEX | 用户ID • 复合索引组成部分 • 用户群组反向查询 • 权限验证使用 |
Nickname | string | 无 | 群内昵称 • 群内显示名称 • 可与全局昵称不同 • 群主管理员可修改 |
FaceURL | string | 无 | 头像URL • 用户头像链接 • 群内头像显示 • 同步全局头像变更 |
RoleLevel | int32 | INDEX | 角色等级 • 20 = 普通成员 (GroupOrdinaryUsers) • 60 = 管理员 (GroupAdmin) • 100 = 群主 (GroupOwner) • 权限控制核心字段 |
JoinTime | time.Time | INDEX | 加入时间 • 成员入群时间记录 • 排序和统计使用 • 成员资历判断 |
JoinSource | int32 | 无 | 加入来源 • 入群渠道统计 • 推广效果分析 • 成员质量评估 |
InviterUserID | string | 无 | 邀请者ID • 邀请关系链 • 社交网络分析 • 成员来源追踪 |
OperatorUserID | string | 无 | 操作者ID • 最后操作记录 • 管理操作审计 • 权限变更追踪 |
MuteEndTime | time.Time | 无 | 禁言结束时间 • 禁言功能支持 • 自动解禁机制 • 群管理工具 |
Ex | string | 无 | 扩展字段 • 成员自定义属性 • 业务数据扩展 • JSON格式存储 |
3. GroupRequest - 群申请表
集合名 : group_request
完整字段结构
字段名 | 字段类型 | 索引 | 详细描述 |
---|---|---|---|
_id | ObjectId | PRIMARY KEY | MongoDB主键 |
UserID | string | INDEX | 申请者用户ID • 复合索引:user_id + group_id • 申请者标识 • 申请历史查询 |
GroupID | string | INDEX | 目标群组ID • 复合索引组成部分 • 群组申请管理 • 批量处理支持 |
HandleResult | int32 | INDEX | 处理结果 • 0 = 待处理 (默认状态) • 1 = 同意 (GroupResponseAgree) • -1 = 拒绝 (GroupResponseRefuse) • 申请状态过滤索引 |
ReqMsg | string | 无 | 申请消息 • 申请者入群理由 • 管理员审核参考 • 申请质量评估 |
HandledMsg | string | 无 | 处理消息 • 管理员处理说明 • 拒绝/同意原因 • 申请者反馈信息 |
ReqTime | time.Time | INDEX | 申请时间 • 申请发起时间 • 申请列表排序 • 处理时效统计 |
HandleUserID | string | 无 | 处理者ID • 处理申请的管理员 • 管理操作追踪 • 权限验证使用 |
HandledTime | time.Time | 无 | 处理时间 • 申请处理时间 • 处理效率统计 • 时效性分析 |
JoinSource | int32 | 无 | 申请来源 • 申请渠道统计 • 与成员加入来源对应 • 转化率分析 |
InviterUserID | string | 无 | 邀请者ID • 邀请类申请的邀请者 • 邀请关系维护 • 社交网络构建 |
Ex | string | 无 | 扩展字段 • 申请相关扩展数据 • 自定义申请属性 • 业务数据支持 |
🚀 Redis 缓存层
OpenIM Redis缓存采用分层过期策略和智能预加载,特别针对群聊场景优化:
1. 群组信息相关缓存
缓存Key格式 | 数据类型 | TTL时间 | 缓存内容 | 使用场景 |
---|---|---|---|---|
GROUP_INFO:{groupID} |
Hash | 24小时 | 完整群组信息 | 群组详情快速查询 |
GROUP_MEMBER_IDS:{groupID} |
Set | 12小时 | 群成员用户ID集合 | 群消息推送,权限验证 |
GROUP_MEMBER_INFO:{groupID}:{userID} |
Hash | 12小时 | 单个成员详细信息 | 成员信息快速查询 |
GROUP_MEMBER_NUM_CACHE:{groupID} |
String | 6小时 | 群成员数量 | 成员统计,群容量检查 |
GROUP_OWNER:{groupID} |
Hash | 24小时 | 群主信息 | 权限验证,管理操作 |
2. 群成员角色相关缓存
缓存Key格式 | 数据类型 | TTL时间 | 缓存内容 | 使用场景 |
---|---|---|---|---|
GROUP_ADMINS:{groupID} |
Set | 12小时 | 管理员用户ID集合 | 管理权限快速验证 |
GROUP_MEMBERS_ALL:{groupID} |
List | 6小时 | 全部成员信息列表 | 成员列表展示 |
GROUP_ROLE_LEVEL_{roleLevel}:{groupID} |
Set | 12小时 | 指定角色级别成员ID | 按角色查询成员 |
USER_JOINED_GROUPS:{userID} |
Set | 12小时 | 用户加入的群组ID集合 | 用户群组列表 |
USER_MANAGED_GROUPS:{userID} |
Set | 12小时 | 用户管理的群组ID集合 | 管理员权限快速检查 |
3. 群成员哈希缓存
缓存Key格式 | 数据类型 | TTL时间 | 缓存内容 | 使用场景 |
---|---|---|---|---|
GROUP_MEMBER_HASH:{groupID} |
String | 24小时 | 群成员列表哈希值 | 成员变更检测 |
GROUP_MEMBER_VERSION:{groupID} |
Hash | 永久 | 群成员版本信息 | 增量同步控制 |
USER_JOIN_GROUP_VERSION:{userID} |
Hash | 永久 | 用户加群版本信息 | 用户群组同步 |
4. 群申请管理缓存
缓存Key格式 | 数据类型 | TTL时间 | 缓存内容 | 使用场景 |
---|---|---|---|---|
GROUP_REQUEST_COUNT:{groupID} |
String | 30分钟 | 待处理申请数量 | 申请数量统计 |
USER_GROUP_REQUESTS:{userID} |
List | 2小时 | 用户发起的群申请 | 申请历史查询 |
GROUP_PENDING_REQUESTS:{groupID} |
List | 1小时 | 群组待处理申请 | 申请管理页面 |
第三部分:群组管理操作权限矩阵
🔐 群组操作权限控制表
OpenIM群组系统采用严格的分级权限控制机制,根据用户角色不同,拥有不同的操作权限。以下表格详细列出了所有群组管理操作及其对应的角色权限:
操作名称 | 功能描述 | 系统管理员 | 群主 | 管理员 | 普通成员 | 特殊说明 |
---|---|---|---|---|---|---|
CreateGroup | 创建群组 | ✅ | ✅ | ✅ | ✅ | 需要通过CheckAccessV3验证权限 |
InviteUserToGroup | 邀请用户加入群组 | ✅ | ✅ | ✅ | ⚠️ | 普通成员在需验证群组中只能发起申请 |
KickGroupMember | 踢出群组成员 | ✅ | ✅ | ⚠️ | ❌ | 管理员不能踢出群主和其他管理员 |
QuitGroup | 退出群组 | ✅ | ❌ | ✅ | ✅ | 群主不能退出群组,需先转让群主 |
SetGroupInfo | 设置群组信息 | ✅ | ✅ | ✅ | ❌ | 修改群名称、头像、公告等信息 |
SetGroupInfoEx | 扩展设置群组信息 | ✅ | ✅ | ✅ | ❌ | 扩展版本的群组信息设置 |
TransferGroupOwner | 转让群主 | ✅ | ✅ | ❌ | ❌ | 只有群主可以转让群主身份 |
DismissGroup | 解散群组 | ✅ | ✅ | ❌ | ❌ | 解散群组是不可逆操作 |
MuteGroupMember | 禁言群组成员 | ✅ | ✅ | ⚠️ | ❌ | 管理员不能禁言群主和其他管理员 |
CancelMuteGroupMember | 取消禁言群组成员 | ✅ | ✅ | ⚠️ | ❌ | 权限规则同禁言操作 |
MuteGroup | 全群禁言 | ✅ | ✅ | ✅ | ❌ | 禁止所有成员发言 |
CancelMuteGroup | 取消全群禁言 | ✅ | ✅ | ✅ | ❌ | 恢复群组正常发言 |
SetGroupMemberInfo | 设置群成员信息 | ✅ | ✅ | ⚠️ | ⚠️ | 角色权限有复杂的层级控制 |
GroupApplicationResponse | 处理群组申请 | ✅ | ✅ | ✅ | ❌ | 审核加群申请(同意/拒绝) |
JoinGroup | 申请加入群组 | ✅ | ✅ | ✅ | ✅ | 所有用户都可以申请加群 |
GetGroupMemberList | 获取群成员列表 | ✅ | ✅ | ✅ | ✅ | 需要是群组成员或系统管理员 |
GetGroupAllMember | 获取群所有成员 | ✅ | ✅ | ✅ | ✅ | 无特殊权限限制 |
GetGroupsInfo | 获取群组信息 | ✅ | ✅ | ✅ | ✅ | 获取群组基本信息 |
GetGroupMembersInfo | 获取群成员详细信息 | ✅ | ✅ | ✅ | ✅ | 需要是群组成员或系统管理员 |
GetGroupApplicationList | 获取群组申请列表 | ✅ | ✅ | ✅ | ❌ | 查看待处理的加群申请 |
GetUserReqApplicationList | 获取用户申请列表 | ✅ | ✅ | ✅ | ✅ | 查看用户发起的申请(需权限验证) |
🏷️ 权限标识说明
标识 | 含义 | 说明 |
---|---|---|
✅ | 完全权限 | 可以执行该操作,无特殊限制 |
⚠️ | 有条件权限 | 可以执行,但有特定条件或限制 |
❌ | 无权限 | 不能执行该操作 |
🔒 详细权限控制规则
1. 系统管理员权限特性
- 最高权限 :系统管理员通过
authverify.IsAppManagerUid()
验证,拥有所有群组的完全控制权 - 跨群组操作:可以操作任何群组,不受群组成员身份限制
- 权限覆盖:可以绕过大部分业务权限验证
2. 群主权限特性
- 群组所有者:拥有该群组的完全控制权(除了退出群组)
- 不可退出:群主不能直接退出群组,必须先转让群主身份
- 最高管理权:可以踢出任何成员、设置任何成员角色
3. 管理员权限特性
- 有限管理权:可以进行大部分管理操作,但不能操作群主和其他管理员
- 禁言限制:不能禁言群主,对其他管理员的操作受限
- 踢出限制:不能踢出群主和其他管理员
4. 普通成员权限特性
- 基础权限:主要是查看和自我管理权限
- 申请权限:可以申请加入群组、退出群组
- 受限操作:大部分管理操作需要更高权限
5. 特殊权限控制场景
场景 | 权限规则 | 代码实现 |
---|---|---|
角色变更 | 只能降低或保持角色等级,不能提升自己角色 | SetGroupMemberInfo 中的复杂权限验证 |
邀请验证 | 根据群组验证设置决定直接加入还是申请模式 | InviteUserToGroup 中的验证逻辑 |
权限继承 | 高等级角色拥有低等级角色的所有权限 | 各方法中的角色等级比较 |
操作审计 | 所有管理操作记录操作者信息 | OperatorUserID 字段记录 |
Webhook扩展 | 支持业务自定义权限验证逻辑 | 各操作前后的Webhook回调 |
6. 权限验证代码模式
go
// 模式1:系统管理员检查
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
// 非系统管理员需要进一步权限验证
}
// 模式2:群组管理员检查
func (g *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error {
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
groupMember, err := g.db.TakeGroupMember(ctx, groupID, mcontext.GetOpUserID(ctx))
if err != nil {
return err
}
if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) {
return errs.ErrNoPermission.WrapMsg("no group owner or admin")
}
}
return nil
}
// 模式3:群组成员检查
func (g *groupServer) checkAdminOrInGroup(ctx context.Context, groupID string) error {
if authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
return nil
}
// 检查是否为群组成员
}
7. 权限验证函数映射表
验证函数 | 适用操作 | 权限要求 |
---|---|---|
CheckGroupAdmin |
群组管理操作 | 系统管理员 或 群主/管理员 |
checkAdminOrInGroup |
群组信息查询 | 系统管理员 或 群组成员 |
authverify.CheckAccessV3 |
用户相关操作 | 本人操作 或 系统管理员 |
authverify.IsAppManagerUid |
所有操作 | 系统管理员验证 |
第四部分:群组管理操作详细流程分析
🔄 操作关系图谱
在深入分析每个操作的详细流程之前,我们先通过关系图谱了解各个操作之间的依赖和关联关系:
🎯 操作分类与数据流转模式
操作类型 | 典型操作 | 数据流转特点 | 缓存影响范围 | 通知触发 |
---|---|---|---|---|
创建类 | CreateGroup, JoinGroup | 新增数据,大量缓存更新 | 全局影响 | 多用户通知 |
修改类 | SetGroupInfo, MuteGroupMember | 更新数据,局部缓存失效 | 局部影响 | 群组通知 |
删除类 | KickGroupMember, DismissGroup | 删除数据,大量缓存清理 | 广泛影响 | 多用户通知 |
查询类 | GetGroupMemberList, GetGroupsInfo | 读取操作,缓存优先 | 无影响 | 无通知 |
流程类 | GroupApplicationResponse | 状态变更,条件处理 | 条件影响 | 条件通知 |
📊 1. CreateGroup - 创建群组详细流程
- group_id
- group_name
- notification
- face_url
- status=0
- group_type
- need_verification API->>MongoDB: 批量插入group_members集合 Note over MongoDB: 群主成员记录:
- role_level=100
- join_source=1
- join_time=now() API->>MongoDB: 提交事务 Note over API: 4. 缓存清理阶段 API->>Redis: DEL GROUP_INFO:{groupID} API->>Redis: DEL JOIN_GROUPS:{creatorUserID} API->>Redis: DEL GROUP_MEMBER_IDS:{groupID} API->>Redis: DEL GROUP_MEMBER_NUM_CACHE:{groupID} API->>Redis: DEL GROUP_ROLE_LEVEL_MEMBER_IDS:{groupID} loop 每个初始成员 API->>Redis: DEL JOIN_GROUPS:{memberUserID} API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{memberUserID} end Note over API: 5. 版本控制更新 API->>API: setVersion(groups, groupID) API->>API: setSortVersion(group_members, groupID) Note over API: 6. 通知发送阶段 API->>Notify: GroupCreatedNotification Note over Notify: 通知内容类型:
constant.GroupCreatedNotification
会话类型: ReadGroupChatType API->>Conv: SetConversations(创建群组会话) API-->>Client: CreateGroupResp{GroupInfo}
关键Redis Key操作清单:
GROUP_INFO:{groupID}
- DELETE (新群组,确保缓存一致性)GROUP_MEMBERS_HASH2:{groupID}
- DELETE (新群组,确保缓存一致性)GROUP_MEMBER_NUM_CACHE:{groupID}
- DELETEGROUP_MEMBER_IDS:{groupID}
- DELETEJOIN_GROUPS:{userID}
- DELETE (每个初始成员)GROUP_ROLE_LEVEL_MEMBER_IDS:{groupID}:{roleLevel}
- DELETEGROUP_MEMBERS_HASH:{groupID}
- DELETEGROUP_MEMBER_INFO:{groupID}:{userID}
- DELETE
MongoDB操作清单:
groups
集合 - INSERT ONE (新群组记录)group_members
集合 - INSERT MANY (初始成员记录)
👥 2. InviteUserToGroup - 邀请用户加群详细流程
inviter_user_id=操作者ID
req_time=当前时间 end API->>MongoDB: CreateGroupRequest(批量创建申请) loop 每个申请 API->>Notify: JoinGroupApplicationNotification end API-->>Client: 返回成功(申请已创建) else 系统管理员或群主/管理员 Note over API: 继续直接邀请流程 end else 其他验证策略 Note over API: 直接邀请流程 end Note over API: 7. 直接邀请流程 loop 每个被邀请用户 API->>API: 构建GroupMember记录 Note over API: role_level=GroupOrdinaryUsers(20)
join_source=JoinByInvitation(2)
inviter_user_id=操作者ID
join_time=当前时间 end Note over API: 8. Webhook成员加入前回调 API->>Webhook: BeforeMemberJoinGroup Webhook-->>API: 回调结果 Note over API: 9. 批量处理邀请(每批50个) loop 分批处理(每批singleQuantity=50) API->>MongoDB: CreateGroup(批量插入group_members) Note over MongoDB: 事务插入群成员记录
触发缓存清理链式操作 Note over API: 9.1 MongoDB事务操作 MongoDB->>MongoDB: group_members.insertMany() Note over API: 9.2 Redis缓存清理 MongoDB->>Redis: 清理相关缓存 Redis->>Redis: DelGroupMembersHash(groupID) Redis->>Redis: DelGroupsMemberNum(groupID) Redis->>Redis: DelGroupMemberIDs(groupID) loop 每个新成员 Redis->>Redis: DelJoinedGroupID(userID) Redis->>Redis: DelGroupMembersInfo(groupID, userID) end Redis->>Redis: DelGroupAllRoleLevel(groupID) Redis->>Redis: DelMaxJoinGroupVersion(userIDs) Redis->>Redis: DelMaxGroupMemberVersion(groupID) Note over API: 9.3 发送成员加入通知 API->>Notify: GroupApplicationAgreeMemberEnterNotification Note over Notify: 通知类型: MemberEnterNotification
通知对象: 群组所有成员
消息内容: 新成员加入信息 end API-->>Client: InviteUserToGroupResp(成功)
🔍 邀请验证策略详细解析
OpenIM支持三种群组邀请验证策略,通过NeedVerification
字段控制:
验证值 | 常量名 | 验证策略 | 邀请者权限要求 | 行为描述 |
---|---|---|---|---|
0 |
ApplyNeedVerificationInviteDirectly |
申请需验证,邀请直接进 | 无特殊限制 | 任何成员邀请都直接加入群组 |
1 |
AllNeedVerification |
所有人需要验证 | 群主/管理员可直接邀请 | 普通成员邀请创建申请,需管理员审核 |
2 |
Directly |
直接进群 | 无特殊限制 | 所有邀请都直接加入群组 |
💾 数据库操作详细分析
1. MongoDB事务操作
直接邀请模式的MongoDB操作:
javascript
// 批量插入群成员记录
db.group_members.insertMany([
{
"group_id": "group_12345",
"user_id": "user_67890",
"role_level": 20, // GroupOrdinaryUsers
"join_source": 2, // JoinByInvitation
"inviter_user_id": "inviter_11111", // 邀请者ID
"operator_user_id": "inviter_11111", // 操作者ID
"join_time": ISODate("2024-01-15T10:30:00.000Z"),
"mute_end_time": ISODate("1970-01-01T00:00:00.000Z")
}
// ... 更多成员记录
])
申请模式的MongoDB操作:
javascript
// 批量插入群申请记录
db.group_requests.insertMany([
{
"group_id": "group_12345",
"user_id": "user_67890",
"join_source": 2, // JoinByInvitation
"inviter_user_id": "inviter_11111", // 邀请者ID
"req_time": ISODate("2024-01-15T10:30:00.000Z"),
"handled_time": ISODate("1970-01-01T00:00:00.000Z"),
"handle_result": 0, // 待处理状态
"req_msg": "", // 申请消息(邀请时为空)
"handled_msg": "" // 处理消息(待处理时为空)
}
// ... 更多申请记录
])
2. Redis缓存管理策略
OpenIM采用链式缓存清理机制,确保数据一致性:
缓存清理顺序与原因:
go
// 缓存清理链式操作
c := g.cache.CloneGroupCache()
// 1. 群组成员相关缓存
c = c.DelGroupMembersHash(groupID) // 成员列表哈希,用于变更检测
.DelGroupsMemberNum(groupID) // 成员数量缓存
.DelGroupMemberIDs(groupID) // 成员ID列表缓存
// 2. 用户相关缓存(针对每个新成员)
.DelJoinedGroupID(userID) // 用户加入的群组列表
.DelGroupMembersInfo(groupID, userID) // 单个成员详细信息
// 3. 角色相关缓存
.DelGroupAllRoleLevel(groupID) // 所有角色级别的成员缓存
// 4. 版本控制缓存
.DelMaxJoinGroupVersion(userIDs) // 用户加群版本
.DelMaxGroupMemberVersion(groupID) // 群成员版本
// 执行链式删除
return c.ChainExecDel(ctx)
关键Redis Key分析:
缓存Key模式 | 数据类型 | 作用 | 清理原因 |
---|---|---|---|
GROUP_MEMBERS_HASH:{groupID} |
String | 成员列表哈希值 | 成员变更需重新计算哈希 |
GROUP_MEMBER_NUM:{groupID} |
String | 成员数量 | 新成员加入,数量发生变化 |
GROUP_MEMBER_IDS:{groupID} |
List | 成员ID列表 | 新成员ID需要添加到列表 |
JOIN_GROUPS:{userID} |
Set | 用户参与的群组 | 用户新加入群组 |
GROUP_MEMBERS_INFO:{groupID}:{userID} |
Hash | 成员详细信息 | 新成员信息需要重新加载 |
GROUP_ROLE_LEVEL_*:{groupID} |
Set | 各角色成员列表 | 新成员加入普通成员角色 |
🚪 3. KickGroupMember - 踢出群成员详细流程
管理员不能踢其他管理员 end Note over API: 3. 数据库删除操作 API->>MongoDB: 开启事务 loop 每个被踢用户 API->>MongoDB: DELETE FROM group_members WHERE group_id=? AND user_id=? end API->>MongoDB: 提交事务 Note over API: 4. 大量缓存清理 loop 每个被踢用户 API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{kickedUserID} API->>Redis: DEL JOIN_GROUPS:{kickedUserID} end API->>Redis: DEL GROUP_MEMBER_IDS:{groupID} API->>Redis: DEL GROUP_MEMBER_NUM_CACHE:{groupID} API->>Redis: DEL GROUP_MEMBERS_HASH:{groupID} Note over API: 5. 会话管理 loop 每个被踢用户 API->>Conv: SetConversationMaxSeq(更新会话序号) end Note over API: 6. 版本控制 API->>API: setVersion(group_members, groupID) Note over API: 7. 通知发送 API->>Notify: MemberKickedNotification Note over Notify: 通知对象:
1. 被踢用户:踢出通知
2. 群内其他成员:成员变更通知
通知类型:MemberKickedNotification API-->>Admin: KickGroupMemberResp{Success}
详细缓存操作列表:
删除的Redis Key:
GROUP_MEMBER_INFO:{groupID}:{kickedUserID}
- DELETE (每个被踢用户)JOIN_GROUPS:{kickedUserID}
- DELETE (每个被踢用户)GROUP_MEMBER_IDS:{groupID}
- DELETE (成员ID列表)GROUP_MEMBER_NUM_CACHE:{groupID}
- DELETE (成员数量)GROUP_MEMBERS_HASH:{groupID}
- DELETE (成员哈希)
权限验证规则代码逻辑:
go
// 权限验证逻辑
if operatorRole == constant.GroupOwner {
// 群主可以踢任何人
return true
} else if operatorRole == constant.GroupAdmin {
// 管理员只能踢普通成员
return targetRole == constant.GroupOrdinaryUsers
}
return false
⚙️ 4. SetGroupInfo - 设置群组信息详细流程
具体操作细节:
MongoDB更新操作:
javascript
// 根据不同字段执行不同的更新操作
db.groups.updateOne(
{ "group_id": "groupID" },
{
$set: {
// 群名称变更
"group_name": "新群名称",
// 群公告变更(特殊处理)
"notification": "新公告内容",
"notification_update_time": new Date(),
"notification_user_id": "operatorUserID",
// 其他基础信息
"introduction": "新群介绍",
"face_url": "http://new-avatar.url",
"need_verification": 1,
"look_member_info": 0,
"apply_member_friend": 1
}
}
)
Redis缓存操作:
GROUP_INFO:{groupID}
- DELETE (群组基础信息缓存失效)
通知分发逻辑:
变更字段 | 通知类型 | 通知对象 | 特殊处理 |
---|---|---|---|
group_name | GroupInfoSetNameNotification |
群组所有成员 | 会话标题更新 |
notification | GroupInfoSetAnnouncementNotification |
群组所有成员 | 公告弹窗提醒 |
其他字段 | GroupInfoSetNotification |
群组所有成员 | 基础信息同步 |
👑 5. TransferGroupOwner - 转让群主详细流程
role_level: 100 → 20 API->>MongoDB: UPDATE group_members SET role_level=100 WHERE group_id=? AND user_id=? Note over MongoDB: 新群主升级
role_level: 20/60 → 100 API->>MongoDB: 提交事务 Note over API: 3. 大量缓存清理 API->>Redis: DEL GROUP_OWNER:{groupID} API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{currentOwnerID} API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{newOwnerID} API->>Redis: DEL GROUP_ROLE_LEVEL_MEMBERS:{groupID}:100 API->>Redis: DEL GROUP_ROLE_LEVEL_MEMBERS:{groupID}:20 API->>Redis: DEL GROUP_ROLE_LEVEL_MEMBERS:{groupID}:60 Note over API: 4. 版本控制更新 API->>API: setVersion(group_members, groupID) Note over API: 5. 通知发送 API->>Notify: GroupOwnerTransferredNotification Note over Notify: 通知对象:
1. 原群主:角色变更通知
2. 新群主:群主权限获得
3. 群内成员:群主变更通知 API-->>Owner: TransferGroupOwnerResp{Success}
关键操作分析:
MongoDB事务操作:
javascript
// 事务保证原子性操作
session.withTransaction(() => {
// 降低原群主权限
db.group_members.updateOne(
{ "group_id": groupID, "user_id": currentOwnerID },
{
$set: {
"role_level": 20,
"operator_user_id": currentOwnerID
}
}
);
// 提升新群主权限
db.group_members.updateOne(
{ "group_id": groupID, "user_id": newOwnerID },
{
$set: {
"role_level": 100,
"operator_user_id": currentOwnerID
}
}
);
});
角色相关缓存清理:
GROUP_OWNER:{groupID}
- DELETE (群主信息)GROUP_ROLE_LEVEL_MEMBERS:{groupID}:100
- DELETE (群主角色成员列表)GROUP_ROLE_LEVEL_MEMBERS:{groupID}:20
- DELETE (普通成员角色列表)GROUP_ROLE_LEVEL_MEMBERS:{groupID}:60
- DELETE (管理员角色列表)
🔕 6. MuteGroupMember - 禁言群成员详细流程
禁言权限验证矩阵:
操作者角色 | 被禁言者角色 | 操作结果 | 说明 |
---|---|---|---|
群主 | 任何角色 | ✅ 允许 | 群主拥有最高权限 |
管理员 | 普通成员 | ✅ 允许 | 管理员可以禁言普通成员 |
管理员 | 管理员 | ❌ 禁止 | 管理员间平级,不能相互操作 |
管理员 | 群主 | ❌ 禁止 | 管理员不能操作群主 |
普通成员 | 任何角色 | ❌ 禁止 | 普通成员无禁言权限 |
MongoDB更新字段:
javascript
{
"mute_end_time": new Date(Date.now() + mutedSeconds * 1000),
"operator_user_id": operatorUserID
}
Redis缓存影响:
GROUP_MEMBER_INFO:{groupID}:{mutedUserID}
- DELETE (成员信息缓存)
📋 7. GetGroupMemberList - 获取群成员列表详细流程
缓存策略分析:
三级缓存架构:
- 本地缓存:进程内缓存,最快访问速度
- Redis缓存:分布式缓存,支持集群共享
- MongoDB:持久化存储,数据源头
Redis Key使用:
GROUP_MEMBER_IDS:{groupID}
- List类型,存储成员ID列表GROUP_MEMBER_INFO:{groupID}:{userID}
- Hash类型,存储成员详细信息
分页查询优化:
javascript
// MongoDB聚合查询,支持高效分页
db.group_members.aggregate([
{ $match: { "group_id": groupID } },
{ $sort: {
"role_level": -1, // 按角色等级倒序(群主>管理员>普通成员)
"join_time": 1 // 同等级按加入时间正序
}},
{ $skip: offset },
{ $limit: pageSize }
]);
📝 8. GroupApplicationResponse - 处理群组申请详细流程
详细数据操作:
同意申请的事务操作:
javascript
// MongoDB事务确保数据一致性
session.withTransaction(() => {
// 1. 更新申请状态
db.group_requests.updateOne(
{
"group_id": groupID,
"user_id": applicantUserID,
"handle_result": 0 // 仅处理待处理的申请
},
{
$set: {
"handle_result": 1, // 1=同意
"handled_msg": "欢迎加入群组",
"handle_user_id": handlerUserID,
"handled_time": new Date()
}
}
);
// 2. 创建群成员记录(如果用户不在群中)
db.group_members.insertOne({
"group_id": groupID,
"user_id": applicantUserID,
"role_level": 20, // 普通成员
"join_source": 3, // 通过申请加入
"join_time": new Date(),
"operator_user_id": handlerUserID,
"mute_end_time": new Date(0)
});
});
拒绝申请操作:
javascript
// 仅更新申请状态,不创建成员记录
db.group_requests.updateOne(
{ "group_id": groupID, "user_id": applicantUserID },
{
$set: {
"handle_result": -1, // -1=拒绝
"handled_msg": "申请被拒绝",
"handle_user_id": handlerUserID,
"handled_time": new Date()
}
}
);
缓存清理操作:
GROUP_MEMBER_IDS:{groupID}
- DELETE (成员列表)GROUP_MEMBER_NUM_CACHE:{groupID}
- DELETE (成员数量)JOIN_GROUPS:{applicantUserID}
- DELETE (申请者加群列表)GROUP_PENDING_REQUESTS:{groupID}
- DELETE (待处理申请列表)
通知发送逻辑:
处理结果 | 通知类型 | 通知对象 | 通知内容 |
---|---|---|---|
同意 | GroupApplicationAcceptedNotification |
申请者 | "您的入群申请已通过" |
同意 | MemberEnterNotification |
群组成员 | "XXX加入了群组" |
拒绝 | GroupApplicationRejectedNotification |
申请者 | "您的入群申请被拒绝" |
🏠 9. QuitGroup - 退出群组详细流程
XXX退出了群组 API-->>Client: 退群成功 end end
群主退群特殊逻辑:
go
// 群主退群权限检查
func (g *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) (*pbgroup.QuitGroupResp, error) {
// 1. 获取操作者在群中的信息
member, err := g.db.TakeGroupMember(ctx, req.GroupID, req.UserID)
if err != nil {
return nil, err
}
// 2. 群主退群特殊处理
if member.RoleLevel == constant.GroupOwner {
// 查询群成员总数
memberCount, err := g.db.FindGroupMemberNum(ctx, req.GroupID)
if err != nil {
return nil, err
}
if memberCount == 1 {
// 仅群主一人,解散群组
return g.DismissGroup(ctx, &pbgroup.DismissGroupReq{
GroupID: req.GroupID,
UserID: req.UserID,
})
} else {
// 还有其他成员,需要先转让群主
return nil, errs.ErrArgs.WrapMsg("群主需要先转让群主权限才能退群")
}
}
// 3. 普通成员直接退出
return g.quitGroupDirectly(ctx, req)
}
数据一致性保证:
- MongoDB删除操作:确保成员记录彻底删除
- Redis缓存清理:避免脏数据,保证缓存一致性
- 会话序号更新:确保消息同步的准确性
- 版本控制更新:支持增量同步机制
💀 10. DismissGroup - 解散群组详细流程
通知内容:群组已解散
触发客户端会话删除 API-->>Owner: DismissGroupResp{Success}
解散群组的数据清理范围:
MongoDB删除操作:
javascript
// 事务保证数据一致性
session.withTransaction(() => {
// 1. 删除所有群成员
db.group_members.deleteMany({ "group_id": groupID });
// 2. 删除群组记录
db.groups.deleteOne({ "group_id": groupID });
// 3. 删除相关申请记录
db.group_requests.deleteMany({ "group_id": groupID });
});
Redis缓存清理列表:
GROUP_INFO:{groupID}
- DELETEGROUP_MEMBER_IDS:{groupID}
- DELETEGROUP_MEMBER_NUM_CACHE:{groupID}
- DELETEGROUP_OWNER:{groupID}
- DELETEGROUP_MEMBERS_HASH:{groupID}
- DELETEGROUP_MEMBER_INFO:{groupID}:{userID}
- DELETE (每个成员)JOIN_GROUPS:{userID}
- DELETE (每个成员)GROUP_PENDING_REQUESTS:{groupID}
- DELETEGROUP_REQUEST_COUNT:{groupID}
- DELETE
通知影响分析:
- GroupDismissedNotification:通知所有群成员群组已解散
- 会话清理:触发客户端删除群组会话
- 数据同步:版本控制确保所有设备同步解散状态
以上详细解析了OpenIM群聊管理的核心功能模块和完整的权限控制体系。每个功能都包含完整的权限验证、数据存储、缓存管理和通知机制,确保群组管理的安全性、一致性和用户体验。完善的权限矩阵为系统提供了精细化的访问控制,满足不同场景下的安全需求。