1. 引言权限管理是几乎所有多用户系统的核心难题。很多团队在初期只做“登录 角色”上线后才发现用户 A 能看用户 B 的私有数据、两个部门共用了同一份资源却互相覆盖、离职员工的权限迟迟没有回收……这些问题的根源往往在于没有把“用户资格”和“资源空间”这两个维度分开设计。本文从你提出的两个关键诉求出发——每个用户具有自己使用权限资源的资格、多个用户共同占有同一个空间——梳理一套可落地的权限模型并给出数据库设计与代码示例。2. 先厘清两个核心概念资格Entitlement与空间Space在动手设计之前先把需求拆成两个正交的维度资格Entitlement描述“某个用户能不能做某件事”。例如“张三可以编辑文档”“李四可以管理成员”。它回答的是Who can do What。空间Space描述“资源归属于哪个容器”。例如“项目 A 的文档库”“团队 B 的共享文件夹”。它回答的是Where the resource lives。你提到的“每个用户具有自己使用权限资源的资格”本质是资格要落到用户个体“共同占有同样的空间”本质是多个用户共享同一个资源容器。把这两个维度分开就能避免最常见的错误把“谁能访问”和“资源在哪”混在一张表里导致共享空间里每个人的权限无法独立控制。3. 推荐模型RBAC 资源空间隔离业界最稳妥的组合是RBAC基于角色的访问控制 资源空间Space隔离用RBAC管理“资格”用户 → 角色 → 权限点。用Space管理“空间”资源挂在某个 Space 下Space 再与用户/角色建立授权关系。这样既保留了角色的复用性又能做到“同一个空间里不同用户拥有不同资格”。3.1 核心实体实体说明示例User用户张三Role角色一组权限的集合管理员、编辑者、访客Permission权限点最小操作单元doc:edit、doc:viewSpace资源空间容器项目 A、团队 BSpaceMember空间成员用户在某空间内的角色张三在项目 A 中是编辑者3.2 关键设计空间成员表“共同占有同一个空间”的核心落点就是SpaceMember这张表。它把“用户”和“空间”关联起来并记录该用户在这个空间内的角色CREATETABLEspace_member(idBIGINTPRIMARYKEYAUTO_INCREMENT,space_idBIGINTNOTNULLCOMMENT空间ID,user_idBIGINTNOTNULLCOMMENT用户ID,role_idBIGINTNOTNULLCOMMENT角色ID在该空间内生效,created_atDATETIMEDEFAULTCURRENT_TIMESTAMP,UNIQUEKEYuk_space_user(space_id,user_id))COMMENT空间成员表用户在某空间内的资格;通过这张表你可以回答两个关键问题“张三在项目 A 里能做什么” → 查space_member得到角色再映射到权限点。“项目 A 里有哪些成员” → 按space_id查space_member。4. 权限判断的核心流程当用户发起一次操作比如“编辑项目 A 的文档”时判断流程如下找到资源所属的Space。查space_member得到该用户在这个 Space 内的Role。由 Role 映射出Permission集合。判断所需权限点是否在集合中。publicclassPermissionService{privatefinalSpaceMemberMapperspaceMemberMapper;privatefinalRolePermissionMapperrolePermissionMapper;publicbooleancheckPermission(LonguserId,LongspaceId,StringpermissionCode){// 1. 用户在空间内的角色SpaceMembermemberspaceMemberMapper.findBySpaceIdAndUserId(spaceId,userId);if(membernull){returnfalse;// 不是空间成员默认无权限}// 2. 角色对应的权限点ListStringcodesrolePermissionMapper.findPermissionCodesByRoleId(member.getRoleId());returncodes.contains(permissionCode);}}5. 如何兼顾“个人资格”与“共享空间”你提到的两个诉求在模型里分别对应两种授权方式5.1 个人专属资格当某个用户拥有独立于任何空间的资格时例如“全局管理员”“仅查看自己的数据”可以在user_role表中记录用户的全局角色或在space_member中为每个用户创建一个私有空间Personal Space把个人资源挂进去。CREATETABLEuser_role(idBIGINTPRIMARYKEYAUTO_INCREMENT,user_idBIGINTNOTNULL,role_idBIGINTNOTNULL,UNIQUEKEYuk_user_role(user_id,role_id))COMMENT用户全局角色表与空间无关的资格;5.2 共享空间内的差异化资格多个用户共同占有同一个 Space但各自资格不同用户空间角色可执行操作张三项目 A编辑者编辑、评论李四项目 A访客仅查看王五项目 A管理员编辑、删除、管理成员这正是space_member表的价值同一个 space_id不同 user_id不同 role_id。6. 权限判断的完整时序数据库PermissionService业务接口用户数据库PermissionService业务接口用户请求编辑项目A的文档checkPermission(userId, spaceId, doc:edit)查询 space_member返回角色 roleId查询 role_permission返回权限点集合是否包含 doc:edit允许 / 拒绝7. 常见坑与建议不要把权限写死在业务代码里用if (user.isAdmin())这种散落判断后期会失控。统一走权限点校验。空间删除前先清理成员关系避免产生孤儿数据。权限点要足够细至少拆到“查看 / 编辑 / 删除 / 管理成员”级别方便后续做细粒度控制。缓存角色-权限映射权限判断是高频操作建议把role_permission缓存到 Redis减少数据库压力。超管与空间管理员分开全局超管走user_role空间管理员走space_member两者互不干扰。8. 总结权限管理的核心是把“资格”和“空间”两个维度解耦资格用 RBAC 管理落到用户个体空间用 Space 容器管理多个用户通过space_member共享同一空间并在空间内拥有各自独立的角色。这样既满足了“每个用户具有自己使用权限资源的资格”也实现了“共同占有同样的空间”。按这个模型落地后续无论是加新空间、调成员角色还是做细粒度权限都能平滑扩展。