inf*_*rno 49 security domain-driven-design access-control
我读到了DDD和访问控制,我发现以下两种观点之间存在一些矛盾:
我正在寻找关于此的最佳实践.那么我应该在哪里通过域驱动设计放置访问控制逻辑,我应该如何实现它?
(更具体地说,DDD + CQRS + ES.)
我认为它应该接近业务逻辑,例如用户故事可能是这样的:
用户可以通过发送用户名,爱好列表,简历等来编辑他的个人资料...
根据用户故事,我们实现了域模型和服务,例如:
UserService
editProfile(EditUserProfileCommand command)
User user = userRepository.getOneById(command.id)
user.changeName(command.name)
user.changeHobbies(command.hobbies)
user.changeCV(command.cv)
UserRepository
User getOneById(id)
User
changeName(String name)
changeHobbies(String[] hobbies)
changeCV(String cv)
Run Code Online (Sandbox Code Playgroud)
这没关系,但HIS profile故事的一部分在哪里?
这显然是基于属性的访问控制,因为我们应该写一个这样的规则:
deny all, but if subject.id = resource.owner.id then grant access
Run Code Online (Sandbox Code Playgroud)
但是我们应该在哪里执行这条规则,我们应该如何实施呢?
inf*_*rno 40
那我应该把访问控制逻辑放在哪里呢?
根据这个:https://softwareengineering.stackexchange.com/a/71883/65755政策执行点应该在调用之前UserService.editProfile().
我得出了相同的结论:它不能在UI中,因为通过多个UI,我们将重复代码.它应该在创建域事件之前,因为它们表明我们已经在系统中做了一些事情.因此,我们可以限制对域对象或使用这些域对象的服务的访问.通过CQRS,我们不需要读取模型的域对象,只需要服务,因此如果我们需要通用解决方案,我们必须限制对服务的访问.我们可以将访问决策放在每个服务操作的开头,但这将是grant all, deny x安全反模式.
我该如何实施呢?
这取决于哪个访问控制模型适合域,因此它取决于用户故事.通过访问决策,我们通常会发送访问请求并等待权限作为回报.访问请求通常包含以下部分:主题,资源,操作,环境.因此,主题需要许可才能对环境中的资源执行操作.首先,我们确定主题,然后我们对其进行身份验证,然后在授权之后,我们检查访问请求是否适合我们的访问策略.每个访问控制模型都以类似的方式工作.OFC.他们可能缺少一些这些步骤,但这无关紧要......
我创建了一个访问控制模型的简短列表.我将规则,策略放入注释中,但通常我们应该将它们存储在可能采用XACML格式的数据库中,如果我们想要一个维护良好的系统......
通过基于身份的访问控制(IBAC),我们拥有身份 - 权限存储(访问控制列表,功能列表,访问控制矩阵).因此,例如通过访问控制列表,我们存储可以具有权限的用户或组的列表.
UserService
@AccessControlList[inf3rno]
editProfile(EditUserProfileCommand command)
Run Code Online (Sandbox Code Playgroud)通过基于格的访问控制(LBAC),主体具有间隙级别,资源具有所需的间隙级别,并且我们检查哪个级别更高......
@posseses[level=5]
inf3rno
UserService
@requires(level>=3)
editProfile(EditUserProfileCommand command)
Run Code Online (Sandbox Code Playgroud)通过基于角色的访问控制(RBAC),我们定义主题角色,并向作为实际角色的主体授予权限.
@roles[admin]
inf3rno
UserService
@requires(role=admin)
editProfile(EditUserProfileCommand command)
Run Code Online (Sandbox Code Playgroud)通过基于属性的访问控制(ABAC),我们定义主题,资源和环境属性,并根据它们编写策略.
@attributes[roles=[admin]]
inf3rno
UserService
@policy(subject.role=admin or resource.owner.id = subject.id)
editProfile(EditUserProfileCommand command)
@attribute(owner)
Subject getOwner(EditUserProfileCommand command)
Run Code Online (Sandbox Code Playgroud)通过基于策略的访问控制(PBAC),我们不会将我们的策略分配给其他任何策略,它们是独立的.
@attributes[roles=[admin]]
inf3rno
UserService
editProfile(EditUserProfileCommand command)
deleteProfile(DeleteUserProfileCommand command)
@attribute(owner)
Subject getOwner(EditUserProfileCommand command)
@permission(UserService.editProfile, UserService.deleteProfile)
@criteria(subject.role=admin or resource.owner.id = subject.id)
WriteUserServicePolicy
Run Code Online (Sandbox Code Playgroud)通过风险自适应访问控制(RAdAC),我们的决策基于主体的相对风险概况和操作的风险级别.我认为这不能用规则来描述.我不确定实现,也许这就是stackoverflow其点系统所使用的.
通过基于授权的访问控制(ZBAC),我们不进行身份验证和身份验证,而是为身份识别因素分配权限.例如,如果有人发送令牌,那么她可以访问服务.其他一切与之前的解决方案类似.例如ABAC:
@attributes[roles=[editor]]
token:2683fraicfv8a2zuisbkcaac
ArticleService
@policy(subject.role=editor)
editArticle(EditArticleCommand command)
Run Code Online (Sandbox Code Playgroud)
所以知道2683fraicfv8a2zuisbkcaac令牌的每个人都可以使用该服务.
等等...
还有许多其他型号,最佳配合始终取决于客户的需求.
总结一下
- "security concerns should be handled outside the domain"
- "access control requirements are domain specific"
Run Code Online (Sandbox Code Playgroud)
两者都可以,因为安全性不是域模型的一部分,但它的实现取决于域模型和应用程序逻辑.
2年后编辑 2016-09-05
自从我作为DDD新手回答我自己的问题以来,我已经阅读了Vaughn Vernon的实现域驱动设计.这是一本有趣的书.以下是它的引用:
这构成了一个新的有界上下文 - 身份和访问上下文 - 并将由其他有界上下文通过标准DDD集成技术使用.对于消费上下文,身份和访问上下文是通用子域.该产品将命名为IdOvation.
因此根据Vernon可能是将访问控制移动到通用子域的最佳解决方案.