域驱动设计中的访问控制

时间:2014-05-05 04:16:25

标签: security domain-driven-design access-control

我读到有关DD​​D和访问控制的内容,我发现以下两种观点之间存在一些矛盾:

  • "安全问题应在域外进行处理"
  • "访问控制要求是特定于域的"

我正在寻找关于此的最佳实践。那么我应该在哪里通过域驱动设计放置访问控制逻辑,我应该如何实现它呢?

(更具体地说,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)

这没关系,但故事的HIS profile部分在哪里?

这显然是基于属性的访问控制,因为我们应该编写如下规则:

deny all, but if subject.id = resource.owner.id then grant access

但是我们应该在哪里执行这条规则,我们应该如何实施呢?

1 个答案:

答案 0 :(得分:36)

  

那么我应该把访问控制逻辑放在哪里呢?

根据这一点: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)
    
  • 通过基于格的访问控制(LBAC),主体具有许可级别,资源具有所需的许可级别,并且我们检查哪个级别更高......

    @posseses[level=5]
    inf3rno
    
    UserService
        @requires(level>=3)
        editProfile(EditUserProfileCommand command)
    
  • 通过基于角色的访问控制(RBAC),我们定义了主题角色,并且我们授予对其行为起实际作用的主体的权限。

    @roles[admin]
    inf3rno
    
    UserService
        @requires(role=admin)
        editProfile(EditUserProfileCommand command)
    
  • 通过基于属性的访问控制(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)
    
  • 通过基于策略的访问控制(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
    
  • 通过风险自适应访问控制(RAdAC),我们根据受试者的相对风险状况和操作的风险等级做出决策。我认为这不能用规则来描述。我不确定实现,也许这就是stackoverflow它的点系统所使用的。

  • 通过基于授权的访问控制(ZBAC),我们不进行身份验证和身份验证,而是为身份识别因素分配权限。例如,如果有人发送令牌,那么她可以访问服务。其他一切与之前的解决方案类似。例如,使用ABAC:

    @attributes[roles=[editor]]
    token:2683fraicfv8a2zuisbkcaac
    
    ArticleService
        @policy(subject.role=editor)
        editArticle(EditArticleCommand command)
    

    所以知道2683fraicfv8a2zuisbkcaac令牌的每个人都可以使用该服务。

依旧......

还有许多其他型号,最适合的总是取决于客户的需求。

总结

- "security concerns should be handled outside the domain"
- "access control requirements are domain specific"

两者都可以,因为安全性不是域模型的一部分,但它的实现取决于域模型和应用程序逻辑。

2年后修改 2016年9月5日

由于我作为DDD新手回答了我自己的问题,我已经阅读了Vaughn Vernon的Implementing Domain-Driven Design。这是一本有趣的书。以下是它的引用:

  

这构成了一个新的有界上下文 - 身份和访问   上下文 - 并将通过标准由其他有界上下文使用   DDD集成技术。对于消费环境而言,身份和   Access Context是一个通用子域。该产品将被命名   IdOvation。

因此根据Vernon可能是将访问控制移动到通用子域的最佳解决方案。

相关问题