提问人:jimmy_terra 提问时间:8/9/2018 最后编辑:TylerHjimmy_terra 更新时间:11/7/2018 访问量:3128
在 DDD 中在哪里实现聚合级别权限?[关闭]
Where to implement aggregate level permissions in DDD? [closed]
问:
假设我有一个聚合类型 ,其中包含 。根据订单的状态和对订单进行操作的用户角色,可能允许或不允许操作。Order
OrderItems
例如,如果用户角色是 ,订单的状态是 ,则允许添加和删除项目。相反,如果订单的状态为“则不允许添加和删除项目”。但是,如果用户角色是,并且订单的状态是,则允许添加和删除项目。Customer
Open
Processing
Manager
Processing
我的问题是:
- 该类型是否应该处理这些类型的权限?也就是说,它封装了关于哪些角色可以做什么的所有逻辑,因此依赖于用户角色。
Order
- 或者,这是否应该在权限服务中的类型之外进行处理,该服务将接受角色、操作和操作的主题(订单实例)并确定是否允许该操作?即,逻辑被外部化并假定在操作执行之前进行验证,该操作不了解用户角色的概念。
Order
Order
(注意:实际用例要复杂得多,需要大量角色、状态和操作。授权发生在外层,并且已经应用了 - 这个问题是关于实例特定的权限。换句话说,客户有权访问“AddItemToOrder”API 端点,但根据订单的具体状态,实际操作可能会被允许,也可能不允许。
答:
在我正在使用的当前系统中,我通过在我的域对象上创建覆盖层来解决这个问题。我的大多数领域对象都是从接口开始的,我用覆盖层构建不同的功能。
例如:
// Business-relevant features
public interface Order {
...
void removeItem(Sku sku); // Or whatever
}
// Implementation directly in the database, side-steps
// ORM problems, here off-topic, but belongs to example
public final class DatabaseOrder implements Order {
...
public DatabaseOrder(Connection connection) {
this.connection = connection;
}
@Override
public void removeItem(Sku sku) {
connection.update(...);
}
}
// This is the "authorization"
public final class AuthorizingOrder implements Order {
private final Order delegate;
private final User user;
public AuthorizingOrder(User user, Order delegate) {
this.user = user;
this.delegate = delegate;
}
...
@Override
public void removeItem(Sku sku) {
if (user.isManager()) {
delegate.removeItem(sku);
} else {
...
}
}
}
当然,这是一个简单的例子,但你明白了。在此解决方案中,没有外部的非域对象,如服务。一切都与无处不在的语言联系在一起。
有些工厂或建筑商可以将这些东西连接在一起,因此最终系统可以使用具有所有必要功能的对象,即使它们净地分开。Order
评论
getUser()
loadUser()
login(...)
User
我更愿意将访问控制视为应用逻辑而不是域逻辑,因为并非所有域操作调用都来自人类用户并且需要访问控制。将权限放在单独的横切层或不同的边界上下文中也有助于关注点分离。
在您的示例中,我将尝试为客户和经理采取的操作提供不同的域方法名称。丰富无处不在的语言可能是一个很好的仲裁者,当你在为相似但略有不同的概念而苦苦挣扎时。
评论
AddItems()
FixOrder()
我有点觉得你依赖于技术细节,而不是无处不在的语言。无处不在的语言已经告诉你该怎么做了。但我假设你还没有这样的语言,或者至少你还没有通过它来锤击用户权限。
这是我的看法,假设你在问问题时使用了无处不在的语言。让我们看看它会把我们带到哪里。
Given current User has Customer role
And Order status is Open and it has 1 Item
When User adds an Item to Order
Then Order should have 2 items
以下是我如何对这种语言进行建模(作为表现力的单元测试):
//given.
var user = new User(role: new CustomerRole());
var order = new Order(status: OrderStatus.Open, items: new [] { new OrderItem(name: "Item 1", price: 1.00m });
//when.
order.AddItem(byUser: user, item: new OrderItem(name: "Item 2", price: 2.00m));
//then.
Assert.Equal(2, order.Items.Count);
到目前为止,正如我们所看到的,答案就在方法内部的某个地方。最有可能的是,在它里面,你会有一个富有表现力的代码,如下所示:Order.AddItem
public void AddItem(User user, orderItem item)
{
if (user.Role.CanAddOrderItem() && this.Status.IsEqualTo(OrderStatus.Open))
{
this.items.Add(item);
}
}
现在我们可以看到它是由 和 决定的。同样,假设这就是你无处不在的语言听起来的样子。Order
Role
我希望这会有所帮助!
评论
given current user has customer role, and order is open; when user adds *valid item* to order; then order has got one more item
given current user has customer role, and order is closed; when user adds *valid item* to order; then exception is thrown
下一个:您将如何分离课程和学生的场景?
评论
orderAuthorizationService.assertCanChangeItems(user, order)
addItem(Customer customer, ...)
addItem(Manager manager, ...)