Seguindo os princípios do design orientado a domínio,
Digamos que estamos construindo um sistema de gestão de pedidos B2B. Um dos requisitos é que, para cada cliente/pedido/item de pedido, possamos designar pessoas para gerenciar o fluxo de pedidos.
Por exemplo, a BMW quer comprar rolamentos e fixadores e precisamos preparar uma oferta. Neste caso, a BWM é a cliente e o pedido contém dois itens: rolamentos e fixadores.
Mark foi designado para o cliente BMW, portanto, ele tem acesso a todo o pedido. Elon foi designado para o item de pedido de rolamentos, portanto, ele só pode gerenciar este item, por exemplo, ele pode calcular o preço da oferta.
O código poderia ser assim:
public class Order
{
public CustomerId CustomerId { get; }
private List<OrderItem> _items = [];
...
public ChangeOrderHeader() // Only Mark can do that
{
...
}
}
public class OrderItem
{
public OrderId OrderId { get; }
...
public void PrepareOffer() // Available for Mark. Also for Elon if this is the bearing order item
{
...
}
}
A questão: como gerenciar a validação de permissão neste caso?
Meu primeiro pensamento foi tratar a validação de permissão como uma regra de negócios normal, então podemos ter algo assim:
public void PrepareOffer(User user)
{
EnsurePermissions(user); // Validation is in method, it also could be a policy
...
}
O problema é que você precisa passar informações/políticas do usuário para todos os métodos dentro de um agregado. Além disso, no meu entendimento, o domínio deve se preocupar com o quê/como e não com quem .
Outra abordagem poderia ser validar a permissão no repositório, por exemplo, ao salvar o agregado, podemos verificar o que foi modificado e validar as permissões do chamador.
public class Repository(IUserAccessor userAccessor)
{
public Task Save(Order order)
{
var user = userAccessor.GetCurrentUser();
if(order.WasModified())
{
EnsureOrderPermissions(order, user);
}
...
}
}
Essa abordagem não produz sobrecarga de código, mas move a lógica de negócios para a camada de infraestrutura.
A próxima abordagem que me vem à mente é validar as permissões do usuário na camada de aplicação, antes de chamar métodos de domínio.
public OrderService(IUserAccessor userAccessor)
{
public void PrepareOffer(Order order, OrderLineId orderLineId)
{
var user = userAccessor.GetCurrentUser();
EnsureOrderLinePermissions(orderLineId, user);
order.PrepareOrder(orderLineId);
}
}
Nesse caso, temos mais código do que na segunda abordagem, mas parece lógico verificar as permissões na camada de aplicação.
E a última abordagem poderia ser executar uma autorização específica de recurso no nível de autorização do endpoint, mas isso pode ser complicado de implementar.