域驱动设计中的访问控制

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可能是将访问控制移动到通用子域的最佳解决方案.

  • @KyleFong 听起来不错,但我不是这个主题的专家。我什至不明白我怎么得到这么多的赞成票,可能其他人也不是专家。:D (3认同)
  • @乔丹是的,当然,但最终当你开始思考它时,它通常并不重要。例如,管理层正在开会,他们刚刚决定解雇一名员工,并且必须撤销访问权限。该决定已经做出,但尚未有人在系统中采取行动。现实世界中已经存在竞争条件。大多数时候,在执行授权规则时,谁先点击并不重要。访问权限通常甚至会在许多系统中缓存一段时间。 (2认同)