Ideas, dudas y faltantes === [ToC] Estructura de módulos y áreas === aca se proponen los nombres y estructuras de los controladores * **Usuario** : El modelo de usuario está en infraestructura ya que es un componente básico y transversal * Areas * ~~Contrasena~~ * ~~CodigoRecuperacionController~~ * ~~ContrasenaController~~ * ~~RecuperacionContrasenaController~~ * ~~Cuenta~~ * ~~AutenticacionController~~ * Administracion * UsuarioController * **Rol**: El modelo de rol debe estar en infraestructura ya que es un componente básico y transversal * Areas * Administracion * RolController * Permiso o seguridad? * no se como ponerle al RolPermiso * >/rol/{id}/permiso * **Permiso** * **Administracion * PermisoController Estructura de respuesta de los recursos. === Para el caso de un recurso en especifico debemos definir si se entregará una estructura del objeto por ejemplo al realizar un: ``` GET /usuario/12345 Host: bank.example.com Accept: application/vnd.acme.account+json ``` ```json= { "id": 12345, "nombre": "juan", "apellido":"perez" ... } ``` Para el tema de las listas seria algo asi: ``` GET /usuario?CantidadDeRegistros=10&NumeroDePagina=2 Host: bank.example.com Accept: application/vnd.acme.account+json ``` ```json= { "id": 12345, "nombre": "juan", "apellido":"perez" ... }, { "id": 12346, "nombre": "josé", "apellido":"perez" ... } ``` - [x] Tambien podriamos basarnos en las estructuras de salida de un objeto o recurso podemos formatearla basandose en una especificación o propuesta de estandar por ejemplo JSON:API (el cual se podria seguir la estructura, donde no necesariamente seria un json, sino que tambien podria ser un XML) Mismo ejemplo: ```json= "datos": [ { "tipo": "usuario", "id": "12346", "atributos": { "nombre": "josé", "apellido": "perez", } } ] ``` Lista ```json= { "meta": { "PaginasTotales": 2 }, "datos": [ { "tipo": "usuario", "id": "12345", "atributos": { "nombre": "juan", "apellido": "perez", } }, { "tipo": "usuario", "id": "12346", "atributos": { "nombre": "josé", "apellido": "perez", } } ], "links": { "actual": "http://example.com/usuario?pagina[número]=3&pagina[tamaño]=1", "primero": "http://example.com/usuario?pagina[número]=1&pagina[tamaño]=1", "anterior": "http://example.com/usuario?pagina[número]=2&pagina[tamaño]=1", "siguiente": "http://example.com/usuario?pagina[número]=4&pagina[tamaño]=1", "ultimo": "http://example.com/usuario?pagina[número]=13&pagina[tamaño]=1" } } ``` otros ejemplos de especificación de respuestas: https://developer.atlassian.com/server/confluence/pagination-in-the-rest-api/ Posicion y Cantidad https://support.smartbear.com/qacomplete/docs/developer/api/rest/api/reference/paging.html https://www.algolia.com/doc/api-reference/api-parameters/offset/ https://www.moesif.com/blog/technical/api-design/REST-API-Design-Filtering-Sorting-and-Pagination/ https://nordicapis.com/everything-you-need-to-know-about-api-pagination/ https://developer.box.com/guides/api-calls/pagination/offset-based/ Filtros de listas ---- Para los filtros se usaran los siguientes operadores: eq—equals gt—greater than gte—greater than or equal has—contains the specified string lt—less than lte—less than or equal in—any of [list] (for searching tags) de esta forma: * *filter=lastLogin:gte:2016-01-01T00:00:00:00Z,siteRole:eq:Publisher* * *sites/9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d/workbooks?filter=tags:in:[stocks,market]* Referencias: * https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_filtering_and_sorting.htm * https://www.moesif.com/blog/technical/api-design/REST-API-Design-Filtering-Sorting-and-Pagination/ * https://support.americommerce.com/hc/en-us/articles/202836800-API-Searching-and-Filtering ~~tambien deberiamos definir si estarán basadas en el principio HATEOAS y Spring HATEOAS~~ ``` GET /accounts/12345 Host: bank.example.com Accept: application/vnd.acme.account+json HTTP/1.1 200 OK Content-Type: application/vnd.acme.account+json Content-Length: ... ``` ```json= { "account": { "account_number": 12345, "balance": { "currency": "usd", "value": 100.00 }, "links": { "deposit": "/accounts/12345/deposit", "withdraw": "/accounts/12345/withdraw", "transfer": "/accounts/12345/transfer", "close": "/accounts/12345/close" } } } ``` https://www.ionos.es/digitalguide/paginas-web/desarrollo-web/hateoas-que-es-y-cual-es-su-funcion-en-las-api-rest/ ~~cuando aplicarlo?..ya que el HATEOAS da información que no sé si deberia entregar en algunos casos donde involucre la seguridad del usuario o de los roles.~~ HA: "no veo que tenga una ganancia" Ideas === * ~~Aplicar log de actividad como filtro transversal que sea gatillado luego de la ejecución de un endpoin~~t (realizado en api dummy) * Falta investigar la forma de añadir identificadores de la entidad para operaciones CRUD. * Aplicar verificación de permisos a endpoint como filtro que debe ser utilizado como decorador de método Donde?: Como?: * Verificar si en log de error se puede incluir referencia a usuario. Problemas Encontrados === >- [x] **Problema** Cuando un enum tiene 0 y se trata de usar el fluentValidation lo toma como si fuera vacio. **Solución**: Quitar el .NotNull().NotEmpty() del .NotNull().NotEmpty().IsInEnum() de la regla de validacion dejando solo el .IsInEnum(); >- [x] **Problema** No guarda el body request en el log de error ni en log de actividad. **Solución**: Se tenia que agregar un middleware UseRequestBuffering para que conserve el body en toda la execucion. >- [x] **Problema** >Al momento de guardar el log de actividad lo guardaba 4 veces. >**Solución**: >Dejarlo fuera de cuando se añaden los modulos. no dentro del foreach. >- [x] **Problema** >El filtro del log de actividad no toma las solicitudes que tengan error en el FluentValidation >**Solución**: >Añadir la opcion de configuracion del servicio options.SuppressModelStateInvalidFilter = true; >https://stackoverflow.com/questions/59922693/fluentvalidation-use-custom-iactionfilter >- [ ] **Problema** >Cuando hay un campo en el body se duplican los errores. >por ejemplo: ```json= { "Errors": [ { "CampoNombre": "Usuario", "Mensaje": "'Usuario' no debe estar vacío." }, { "CampoNombre": "Usuario", "Mensaje": "'Usuario' no debería estar vacío." } ] } ``` >**Solución**: >Pendiente Dudas === >- [x] Donde irian los unit test? >> *Hemos hecho unittest pero a nivel general. Es decir, como una API completa. no unittest por modulo construido.* >- [x] Uso de CORS en startup >> *Se debe validar si va ir en esta iteración. ya que con los permisos de usuario y perfil tiene un nivel de seguridad aceptable.* >- [x] Vamos a usar fechas UTC >> *Por lo conversado el 31/12 se podrian aplicar para todas las fechas, ya que no es un impedimiento para el sistema, y se se piensa como un producto internacional es recomendable usar las fechas como UTC* >- [x] 2FA opcional por usuario o por sistema. >>*(R: Deberia dejarse a decision del operador o administrador de sistema de que todos los usuarios deberian aplicar 2FA, usuarios especificos o a decisión de cada usuario)* >- [x] ¿El uso del type en el DefaultConnection de appsettings.json es un estandar? >> *Por lo revisado no corresponde a un estandar, sino que es un configuracion personalizada para el uso de los distintos motores de base de datos. Lo malo de aplicarlo asi, es que si requiere aplicar un nuevo tipo en un motor no soportado habria que modificar la insfraestructure. Actualmente estan soporteado "mssql" "npgsql" "mysql"* >- [ ] Revisar por que en el swagger aparece como ejemplo cuando es un enum { "TipoIdentificador": "PorIdentificadorDeUsuario", <- este campo deberia ser un int. "ValorIdentificador": "string" } >- [ ] ¿Como deberian encriptarse los datos de la cabecera? >- [x] Los namespace en la carpeta de support tienen referecias a otras carpetas, ¿eso está bien? >> AM: Indica que está bien, ya que es una agrupación física de las clases. Si necesitamos modificarlo o si tenemos una mejor agrupacion podriamos proponerla. Faltantes === Definiciones > * Modificar documenación de constantes para añadir que los de tipo numerico son "enum" > * Definir validaciones de request (RuleFor) > * Uso de JWT en el autenticacion y en el recuperar contraseña > * Definir en detalle el uso del appsettings.json Base de Datos > * ~~cambiar varchar a nvarchar las tablas faltantes~~ > * pasar rol identity a base de datos de desarrollo. En recuperar contraseña. > * ~~Verificar que un token jwt está usado (por bbdd).~~ > * ~~Cambiar el nombre a la policy de PasswordRecovery a RecuperarContrasena u otro a definir.~~ > * ~~Verificar si usuario posee solicitud de recuperación.~~ ~~> * Limitar tiempo entre solicitudes de recuperación.~~ (No deberia ir, ya que es una validacion de mas.) En autenticación > * ~~Tabla de log de intentos autenticacion~~ > * ~~Llenar tabla de de intentos autenticacion~~ (falta obtener nombreusuario desde body) > * ~~Tabla de lista negra~~ > * ~~tabla de criterios de contraseña~~ > * ~~Validación según criterios de contraseña y como incorporarlo con user identity.~~ > * Pasar a español por localizacion los mensajes nativos del identity validator. > * intentos numeros incorrectos->se debe validar dentro de los mismos controles de criterios de contraseña? > * Implementación autenticación de doble factor (OAuth2) Administracion Usuario > * Definir nombre de controladores. > * Definir listado > HQBDOC EMAIL/SMS > * Creación de interfaz en infraestructura con la definición de método genérico. > * Crear implementaciones de interfaz para cada método de envío. Personalización de validaciones de request > * ~~Averiguar si se puede personalizar las validaciones de Fluent Validation~~ Se pudo crear una validación personalizada para rut's