如何在领域驱动设计(DDD)中适配用户、角色与权限?
如何在DDD中设计用户、角色与权限的聚合模型
针对你提到的场景(权限、角色、用户可独立存续,用户通过角色获取权限),我分享下在DDD中落地的常见设计思路——核心是让每个具备独立业务意义的实体成为自己的聚合根,用领域服务来处理跨聚合的关联逻辑:
1. 定义独立的聚合根
每个实体都有自己完整的业务生命周期,所以各自作为聚合根完全合理:
- User聚合根:封装用户核心属性(如
userId、username、email、accountStatus等),只负责用户自身的业务规则(比如修改密码、禁用账号)。内部维护assignedRoleIds集合,存储已分配的角色ID(而非Role实体本身)。 - Role聚合根:封装角色核心属性(如
roleId、roleName、description),负责角色自身的生命周期(创建、更新、标记删除)。内部维护associatedPermissionIds集合,存储关联的权限ID。 - Permission聚合根:封装权限核心属性(如
permissionId、permissionCode、resourcePath、actionType),负责权限的创建、更新等操作。
2. 用领域服务处理跨聚合的关联操作
用户分配角色、角色关联权限这类操作涉及多个聚合根的协作,不属于单一聚合根的职责,因此交给领域服务来协调:
- UserRoleAssignmentService:
assignRoleToUser(userId: string, roleId: string):先加载User和Role聚合根,验证角色是否可用、用户状态是否正常,然后将roleId添加到User的assignedRoleIds集合;如果业务需要反向查询角色下的用户,也可以同时将userId添加到Role的assignedUserIds集合。removeRoleFromUser(userId: string, roleId: string):同理,移除双方的关联ID。
- RolePermissionAssociationService:
associatePermissionToRole(roleId: string, permissionId: string):加载Role和Permission,验证合法性后,将permissionId添加到Role的associatedPermissionIds集合。disassociatePermissionFromRole(roleId: string, permissionId: string):移除关联ID。
3. 权限校验的实现逻辑
当需要判断用户是否拥有某个权限时,通过领域服务UserPermissionCheckService封装核心逻辑:
public class UserPermissionCheckService { private final UserRepository userRepo; private final RoleRepository roleRepo; private final PermissionRepository permissionRepo; // 构造函数注入依赖 public boolean hasPermission(String userId, String permissionCode) { User user = userRepo.findById(userId); if (user == null || user.getAccountStatus() == AccountStatus.DISABLED) { return false; } List<Role> roles = roleRepo.findByIds(user.getAssignedRoleIds()); Set<String> allPermissionIds = roles.stream() .flatMap(role -> role.getAssociatedPermissionIds().stream()) .collect(Collectors.toSet()); Permission targetPermission = permissionRepo.findByCode(permissionCode); return allPermissionIds.contains(targetPermission.getPermissionId()); } }
这种设计既保证了领域模型的纯净,又通过聚合根的ID关联实现了权限的传递逻辑。
关键设计原则
- 避免跨聚合引用实体:聚合根之间只通过ID关联,不直接持有其他聚合的实体实例,这样每个聚合根可以独立修改、持久化,不会因为其他聚合的变化而受影响。
- 单一聚合根职责:每个聚合根只维护自身的业务一致性,跨聚合的逻辑交给领域服务,符合DDD中聚合根的边界设计要求。
- 保留独立存续能力:删除一个权限时,只需通过领域服务更新所有关联角色的
associatedPermissionIds;删除一个角色时,更新用户的assignedRoleIds,完全不影响其他独立实体的存在。
内容的提问来源于stack exchange,提问作者Liarus
相关产品推荐
相关产品推荐

