Sto lavorando per implementare la mia prima architettura pulita e l'applicazione CQRS, mi sono imbattuto in un po 'di logica che mi ha lasciato un po' perplesso. Sto lavorando per integrare l'autorizzazione e l'autenticazione nella mia applicazione, ma sto avendo qualche problema nel cercare di capire come progettare una parte della mia applicazione che gestirà la convalida dei comandi. Il mio sistema è multitenant e attualmente condivide un database tra tutti i miei clienti, e ho bisogno di implementare una sorta di sistema che mi consenta di eseguire tutte le mie verifiche in un modo semplice e non troppo stretto.
Nel mio sistema, ho implementazioni per Users
e Clients
. Gli utenti possono appartenere a qualsiasi numero di client. Questi utenti hanno anche diversi livelli di permessi a loro assegnati (ma questo è gestito dai miei sistemi di ruoli e per lo più irrilevante qui). My WebAPI è progettato in modo tale da limitare l'autorizzazione in base a un numero fisso di Roles
e Claims
. Questi rimangono in gran parte statici, quindi non ho bisogno di molta flessibilità qui.
La mia principale fonte di mal di testa è determinare le autorizzazioni di interazione "Utente-Cliente". Vale a dire, voglio determinare se un utente ha accesso al client per il quale si è tentato di aggiornare i record. Un approccio sarebbe quello di aggiungere UserId
a tutti i miei comandi e verificare singolarmente le autorizzazioni durante ogni comando e query. Questo sembra noioso e soggetto a problemi.
Un altro approccio che ho considerato era quello di definire un'interfaccia o una classe base che aggiungesse semplicemente gli ID utente e utente a qualsiasi oggetto in cui fossero richiesti, ma questo ha avuto l'effetto negativo di esporre tali implementazioni alle mie WebAPI (tramite swagger e UserId / ClientId è una parte dell'oggetto Request / Command).
Un ultimo approccio sarebbe quello di rendere i miei comandi sottostanti ancora implementare quelle interfacce, ma il mio controller contiene una logica minima per mappare una richiesta API in uno dei miei oggetti comando. Di nuovo, questo sarebbe noioso e inizierebbe a far filtrare la mia logica nei miei controllori.
Nel complesso, è come se avessi bisogno di qualche struttura aggiuntiva nella mia applicazione in cui posso reindirizzare qualsiasi oggetto contenente un ClientId
in modo da poter mantenere la Authentication
e la Authorization
logica dalla mia app principale. Tuttavia, sono per lo più perplesso e sto cercando modi in cui posso semplificare la mia applicazione riducendo al minimo il sovraccarico di aggiunta di comandi e query dipendenti dal client.
Se è pertinente, alcuni degli strumenti e delle tecnologie principali che sto sfruttando sono:
- .Net Core 2.1
- Mediatr
- Entity Framework
E la mia applicazione principale implementa i comandi in modo simile a:
public class CreateProductCommand : IRequest
{
public int ClientId { get;set; }
public int ParentProductId { get; set; }
public string ProductName { get; set; }
// other creation specific props here
}
public class CreateProductCommandHandler : IHandler<CreateProductCommand>
{
public async Task<Unit> Handle(CreateProductCommand command)
{
// check parent permissions, make sure parent product
// belongs to client who is entered.
// -----
// rest of logic to save
// -- Ideally the User-Client check would happen before
// -- the command is ever sent to the handler, so that
// -- only client-specific logic and permissions are checked.
// -- As long as the user can edit the specific client, anything
// -- that happens to the client is determined by standard business
// -- and domain logic.
}
}