假设我的聚合类型为Order
,其中包含OrderItems
。根据订单的状态以及对其进行操作的用户角色,可以允许或不允许进行操作。
例如,如果用户角色为Customer
,订单状态为Open
,则允许添加和删除项目。相反,如果订单的状态为Processing
,则不允许添加和删除商品 。但是,如果用户角色为Manager
,订单状态为Processing
,则允许添加和删除项目 。
我的问题是:
Order
类型是否应处理这些类型的权限?即,它封装了有关哪些角色可以做什么的所有逻辑,因此依赖于用户角色。Order
类型之外进行处理,该服务将接受角色,操作和操作的主题(订单实例),并确定是否允许该操作?也就是说,在Order
上执行操作之前,逻辑已被外部化并假定已被验证,这不了解用户角色的概念。(注意:现实中的用例要复杂得多,具有大量的角色,状态和动作。授权发生在外层并且已经被应用-这个问题与实例特定的权限有关。换句话说,客户有权访问“ AddItemToOrder” API端点,但根据订单的特定状态,可能会或可能不允许实际操作。)
答案 0 :(得分:5)
我更喜欢将访问控制视为应用逻辑而不是域逻辑,因为并非所有域操作调用都将来自人类用户并且需要访问控制。将权限放在单独的跨领域图层或不同的绑定上下文中也有助于分离问题。
在您的示例中,我将尝试为客户和经理采取的操作提出不同的域名方法名称。当您在为相似但略有不同的概念而苦苦挣扎时,丰富无处不在的语言可能是一个不错的选择。
答案 1 :(得分:3)
在当前正在使用的系统中,我通过在域对象上创建叠加层解决了此问题。我的大多数“域对象”都是从界面开始的,并且我使用叠加层构建了不同的功能。
例如:
// 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
对象,即使它们是完全分开的。
答案 2 :(得分:0)
我觉得您是依靠技术细节而不是普遍使用的语言。无所不在的语言已经告诉您该怎么做。但是我认为您还没有这样的语言,或者至少您还没有通过它获得用户权限。
这是我的看法,假设您在问问题时使用了普遍使用的语言。让我们看看它带我们去哪里。
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
决定的。同样,假设这是您无所不在的语言的发音。
我希望这会有所帮助!