【问题标题】:CQRS applying cross cutting concerns such as securityCQRS 应用横切关注点,例如安全性
【发布时间】:2012-02-19 02:27:17
【问题描述】:

假设我有一个复杂的系统,其中有大量的人。简单的想法是员工/经理的关系,许多员工向一位经理汇报。现在除了经理之外,还有能够代表经理行事的支持人员可以操纵经理的员工。

在 CQRS 系统中,您将如何为假设的“编辑员工”操作的消息建模,其中该操作的调用者是支持人员。仅当根据经理安全关系的员工对其领域内的员工执行操作时,该操作才能成功。

验证其安全性将涉及查询数据库以验证被修改的人确实在该经理的员工链中。

这个查询会出现在哪里?在发出“编辑员工”消息之前?

如果在生成消息之前对数据进行了预先验证,那么在最终一致的系统中,假设在处理“编辑员工”消息之前发生了一个单独的操作,该操作将删除用户完成“编辑”的权限员工”的行动。如果命令处理程序没有验证该消息的安全问题,即使用户不再有权执行该消息,该消息仍然会成功。

这似乎意味着双面验证,类似于 UI 验证和服务器端验证将是最好的做法。然而,完成该验证的方法似乎违反了 CQRS 的关键原则。

在使用 CQRS 时必须处理这些和其他类似的横切问题时,哪种方法最好?

【问题讨论】:

  • IMO 没有一般的答案......我总是会在命令处理程序方面验证 至少可选 “预先”(这可能是在接受消息进入队列的部分)
  • 我还认为区分真正的横切关注点(如身份验证、简单授权(是否允许此用户执行此类操作))与管理是否允许某事的业务规则很重要对于特定实体。

标签: security messaging cqrs domain-model cross-cutting-concerns


【解决方案1】:

对于这个域,我可能会完全跳过 CQRS,让 Web 层直接与 DB 层对话(没有消息传递)。简单的乐观并发应该可以处理可能发生的少数冲突。

【讨论】:

  • 你能解释一下你的思考过程,为什么你会发表第一个陈述吗?
  • 因为它是可能可行的最简单的解决方案 :)
  • 这当然是对的,但是如果最简单的做法总是最好的做法,那么根本就不存在 CQRS 模式吗?
  • @ChrisMarisic 简单和天真不一样。与替代方案相比,能够处理纯读取模型而无需涉足复杂业务模型的复杂性可能非常简单。能够对业务行为进行建模也可以更简单,而不必弄清楚真正需要哪些对象的 getter 来执行业务规则,并且只存在于许多视图之一。一般来说,混合读取和写入可以(并且经常这样做)导致无形的混乱,这远非简单。
  • @DennisTraub 我不确定你想表达什么观点,你能改写你的一些评论吗?
【解决方案2】:

首先,我同意@Yahia 的评论,即没有一个普遍的答案。话虽如此,这就是我的处理方式。

首先,我可能会进行双重验证——当第一次收到请求时在我的控制器中进行一次验证,然后在处理命令时在我的域中进行验证。有些人可能不同意这一点,但我宁愿阻止发出命令并立即让用户知道他们无权执行某些操作,而不是让命令通过并​​依靠最终的一致性来发出一些错误通知以发出警报用户在他们无法执行操作之后。

所以,就伪代码而言,这是我编辑员工的方法:

控制器

[HttpPost]
ActionResult Edit(Employee emp){

  //get employee org information from _employeeRepository
  //validate if _loggedInUserID is able to edit emp.ID

  if(isValid) {
    //construct command
    _commandService.EnqueueCommand(new EditEmployee(emp.ID, emp.Name, emp.Salary));
  } else {
    return View("PermissionError");
  }

  return Redirect("EmployeeProperties");
}

因此,我的命令服务在这里获取命令并将其路由到我的域中的适当 AR,即 Employee。

员工域

protected void EditEmployee(userID, employeeID, employeeName, salary){
  //get employee org information from _employeeRepository
  //validate if userID is able to edit employeeID

  if(isValid) {
    //apply event
    ApplyEvent(new EmployeeEdited(userID, employeeID, employeeName, salary));
  }
}

所以我会在我的控制器和域中应用相同的安全检查。我可能会将其作为封装方法(嗯,可能是我将传递给存储库的封装标准类)。

所以我希望这有助于我如何处理这种情况。如果有问题,请告诉我,我会在回答中详细说明。

我希望这会有所帮助。祝你好运!

【讨论】:

  • 为什么要在两个级别上都应用它?域层不是所有东西都应该通过的地方,因此应该在那里处理诸如安全和验证之类的问题吗??
猜你喜欢
  • 2014-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-01
  • 1970-01-01
  • 2020-02-19
  • 1970-01-01
  • 2011-04-01
相关资源
最近更新 更多