5

Supponiamo che io abbia un sistema complesso dove ci sono grandi alberi di persone. I pensieri semplici sono rapporto dipendenti/manager, molti dipendenti riferiscono a un manager. Ora oltre al gestore ci sono staff di supporto che sono in grado di agire per conto del manager in grado di manipolare i dipendenti dei manager.CQRS che applica problemi trasversali come la sicurezza

In un sistema CQRS, come modellare un messaggio per un'ipotetica azione di "modifica dipendente" in cui l'invocatore dell'azione è uno staff di supporto. L'azione può avere successo solo se il membro dello staff in base alla relazione di sicurezza del manager agisce su un dipendente nel suo ambito.

Verificare la sicurezza di ciò richiederebbe l'interrogazione del database per verificare che la persona da modificare sia effettivamente all'interno della catena di dipendenti di quel gestore.

Dove si verifica questa query? Prima di generare il messaggio "modifica dipendente"?

Se i dati vengono convalidati in anticipo prima di dare origine al messaggio, in un sistema eventualmente coerente si supponga che prima che il messaggio "modifica dipendente" sia stato elaborato si è verificata un'azione separata che avrebbe rimosso l'autorizzazione dell'utente per completare il " modifica l'azione "dipendente". Se il gestore comandi non convalida i problemi di sicurezza di quel messaggio, il messaggio continuerà comunque anche se l'utente non ha più l'autorizzazione per eseguirlo.

Ciò sembrerebbe implicare che la convalida su entrambi i lati, simile alla validazione lato server della convalida UI & sarebbe la migliore linea di azione. Tuttavia, il metodo di completamento di tale convalida sembra come se violasse i principi chiave di CQRS.

Quali sono gli approcci migliori quando si ha a che fare con questi e altri problemi trasversali simili quando si utilizza CQRS?

+1

IMO non esiste una risposta generale ... Convaliderei sempre sul lato del gestore comandi * almeno * e ** facoltativamente ** "in avanti" (che potrebbe essere nella parte che accetta un messaggio nella coda) – Yahia

+0

Penso anche che sia importante distinguere tra veri problemi trasversali come l'autenticazione, l'autorizzazione semplice (questo utente è autorizzato a eseguire un'azione di questo tipo), dalle regole aziendali che determinano se qualcosa è permesso per una specifica entità. –

risposta

3

Probabilmente salterò CQRS interamente per questo dominio e il livello Web parlerà direttamente al livello DB (senza messaggi). La semplice concorrenza ottimistica dovrebbe gestire i pochi conflitti che potrebbero verificarsi.

+0

Puoi spiegare il tuo processo di pensiero sul motivo della tua prima affermazione? –

+1

Perché è la soluzione più semplice che potrebbe funzionare :) –

+0

Questo è certamente vero, ma se il più semplice fosse sempre la migliore linea di azione, non esisterebbe affatto l'esistenza del modello CQRS? –

5

In primo luogo, concordo con il commento di @ Yahia che non esiste una risposta generale. Detto questo, ecco come mi avvicinerei.

Per iniziare, probabilmente andrei con la doppia convalida - una volta nel mio controller quando la richiesta è stata ricevuta per la prima volta e poi nel mio dominio mentre sta elaborando il comando. Alcuni potrebbero non essere d'accordo, ma preferirei impedire l'emissione di un comando e far sapere all'utente che non erano autorizzati ad eseguire un'azione piuttosto che far passare il comando e fare affidamento sull'eventuale coerenza per qualche avviso di errore per allertare l'utente dopo il fatto che non potevano eseguire l'azione.

Quindi, in termini di pseudo-codice, ecco il mio approccio alla modifica dei dipendenti:

controller

[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"); 
} 

Quindi, ecco il mio servizio di comando prende il comando e instrada alla AR appropriata nel mio dominio, che sarebbe Dipendente.

dipendenti Domain

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)); 
    } 
} 

Così si applicherebbe lo stesso controllo di sicurezza sia nel mio controller e nel mio dominio. Avrei questo, probabilmente, come un metodo incapsulato (beh, probabilmente una classe di criteri incapsulata che vorrei passare al repository).

Quindi spero che questo aiuti con come vorrei affrontare questo scenario.Fammi sapere se ci sono domande e elaborerò la mia risposta.

Spero che questo aiuti. In bocca al lupo!

+0

Perché dovresti applicarlo a entrambi i livelli? Il livello di dominio non è il punto in cui tutto dovrebbe passare e quindi riguarda la sicurezza e la convalida dovrebbero essere gestiti lì? – Juri