5

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

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

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

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

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

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

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

4

2 回答 2

5

首先,我同意@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));
  }
}

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

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

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

于 2012-01-26T01:50:37.400 回答
4

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

于 2012-01-26T11:59:10.650 回答