假设我有一个复杂的系统,那里有大量的树木。简单的想法是员工/经理关系,许多员工向一位经理报告。现在除了经理之外,还有能够代表经理行事的支持人员可以操纵经理的员工。
在CQRS系统中,您如何为“编辑员工”的假设操作建模消息,其中操作的调用者是支持人员。只有当员工根据经理人的安全关系对其所在领域的员工采取行动时,该行动才能成功。
验证此安全性将涉及查询数据库以验证被修改的人确实在该经理的员工链内。
此查询将在何处发生?在发起“编辑员工”消息之前?
如果在发起消息之前对数据进行了前期验证,则在最终一致的系统中假设在处理“编辑员工”消息之前发生了单独的操作,该操作将删除用户完成“编辑”的权限员工“行动。如果命令处理程序未验证该消息的安全性问题,则即使用户不再具有执行该消息的权限,该消息仍将成功。
这似乎意味着双面验证,类似于UI验证&服务器端验证将是最佳的行动方案。然而,完成该验证的方法似乎违反了CQRS的关键原则。
在使用CQRS时,必须处理这些和其他类似的横切问题时,哪种方法最佳?
答案 0 :(得分: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));
}
}
所以我会在我的控制器和我的域中应用相同的安全检查。我可能会把它作为一个封装的方法(好吧,可能是我将传递给存储库的封装标准类)。
所以我希望这有助于我如何处理这种情况。如果有问题请告诉我,我会在答案中详细说明。
我希望这会有所帮助。祝你好运!
答案 1 :(得分:3)
我可能完全跳过此域的CQRS,并让Web层直接与DB层对话(无消息传递)。简单的乐观并发应该可以处理可能发生的一些冲突。