5

Supongamos que tengo un sistema complejo donde hay grandes árboles de personas. Los pensamientos simples son relación entre empleados/gerente, muchos empleados reportan a un gerente. Ahora, además del gerente, hay personal de soporte que es capaz de actuar en nombre del gerente y puede manipular a los empleados de los gerentes.CQRS aplicando problemas de corte transversal, como la seguridad

En un sistema CQRS, ¿cómo modelaría un mensaje para una acción hipotética de "editar empleado" donde el invocador de la acción es un personal de soporte. La acción solo puede tener éxito si el miembro del personal según la relación de seguridad del gerente actúa sobre un empleado en su reino.

La verificación de la seguridad de esto implicaría consultar la base de datos para validar que la persona que se está modificando está de hecho dentro de la cadena de empleados de ese administrador.

¿Dónde ocurriría esta consulta? ¿Antes de originar el mensaje "editar empleado"?

Si los datos son validados por adelantado antes de originar el mensaje, en un sistema eventualmente consistente suponga que antes de que el mensaje "editar empleado" haya sido procesado se haya producido una acción separada que habría eliminado la autoridad del usuario para completar el " editar acción de los empleados. Si el controlador de comando no valida los problemas de seguridad de ese mensaje, el mensaje seguirá teniendo éxito aunque el usuario ya no tenga la autoridad para ejecutarlo.

Esto parece implicar que la validación de doble cara, similar a la validación de la interfaz de usuario & del lado del servidor, sería la mejor opción. Sin embargo, el método para completar esa validación parece que violaría los principios clave de CQRS.

¿Qué enfoque (es) son mejores cuando se tienen que tratar estos y otros asuntos similares al utilizar CQRS?

+1

IMO no hay una respuesta general ... Siempre validaría en el lado del controlador de comandos * al menos * y ** opcionalmente ** "por adelantado" (que podría estar en la parte que acepta un mensaje en la cola)) – Yahia

+0

También creo que es importante distinguir entre verdaderas preocupaciones transversales como la autenticación, la autorización simple (este usuario puede realizar una acción de este tipo), de las Reglas de negocio que rigen si se permite algo para una entidad específica. –

Respuesta

3

Probablemente omita CQRS por completo para este dominio y haga que el nivel web se comunique directamente con el nivel de DB (sin mensajes). La concurrencia optimista simple debería manejar los pocos conflictos que podrían ocurrir.

+0

¿Puede explicar su proceso de pensamiento en cuanto al por qué de su primera declaración? –

+1

Porque es la solución más simple que podría funcionar :) –

+0

Eso ciertamente es cierto, sin embargo, si el más simple fuera siempre el mejor curso de acción, ¿no existiría en absoluto el patrón CQRS? –

5

En primer lugar, estoy de acuerdo con el comentario de @ Yahia de que no hay una respuesta general. Dicho esto, así es como lo abordaría.

Para empezar, probablemente vaya con la doble validación, una vez en mi controlador cuando la solicitud se recibió por primera vez, y luego en mi dominio, ya que está procesando el comando. Algunos pueden no estar de acuerdo con eso, pero prefiero evitar que se emita un comando e informar inmediatamente al usuario de que no están autorizados para realizar alguna acción en lugar de ejecutar el comando y confiar en la coherencia eventual de un aviso de error para alertar el usuario después del hecho de que no pudieron realizar la acción.

Por lo tanto, en términos de pseudo-código, aquí está mi acercamiento a la edición del empleado:

controlador

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

Así que aquí mi servicio comando toma el mando y lo encamina a la AR apropiada en mi dominio, que sería Empleado.

Empleado dominio

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

Por lo tanto, se aplicaría el mismo control de seguridad, tanto en mi y en mi controlador de dominio. Tendría esto, probablemente, como un método encapsulado (bueno, probablemente una clase de criterios encapsulados que pasaría al repositorio).

Así que espero que esto ayude con la forma en que abordaría este escenario.Avíseme si hay preguntas y elaboraré en mi respuesta.

Espero que esto ayude. ¡Buena suerte!

+0

¿Por qué lo aplicarías en ambos niveles? ¿No es la capa de dominio el punto por el que todo debe pasar y, por lo tanto, preocupaciones como la seguridad y la validación deben ser manejadas allí? – Juri