Manager de Roles & Usuarios: Integración con Back-End
Funcionalidad
A continuación presentamos como integrarse con el backend de Roles&Usuarios así como su librería que engloba una serie de funcionalidades que podrían ser útiles a lo largo del desarrollo de microservicios que necesiten hacer uso del lo configurado en el módulo de Roles y Usuarios.
Esta librería ayuda al usuario a simplificar su código además de ahorrar tiempo de programación que se suele invertir en funcionalidades frecuentes con la administración de roles y usuarios. De este modo, mediante a la importación de esta librería externa, se proporcionan al usuario dichas funcionalidades implementadas en la aplicación.
Alternativas
Esta guía de uso está pensada para la integración directamente con el back-end usando las interfaces que la solución nos aporta para facilitar este propósito. Esencialmente se dan dos alternativas de integración que se verán a continuación.
Altair
Se trata de un cliente para GraphQL que nos facilita el uso de las peticiones a través de la documentación. Con la facilidad de un buscador y un simple click se pueden ir cargando los datos de las peticiones para que solo necesiten ser modificadas, sin necesidad de hacerlas manualmente.
Es la solución que nosotros recomendamos accesible a través del siguiente enlace (en desarrollo): https://dev.architecture.onesait.com/multi-user-roles/altair.
Playground
Se trata de un cliente algo más básico que Altair. Incluye también la documentación para consultar las operaciones que se pueden realizar pero no nos facilita de igual forma su uso. Toda operación realizable con Altair puede hacerse también con esta alternativa.
El enlace para acceder en desarrollo es el siguiente: https://dev.architecture.onesait.com/multi-user-roles/gui
Integración usando Altair
En la siguiente imagen se explican para que sirvan los diferentes iconos que aparecen en la interfaz de Altair.
Configuración previa
Las peticiones que se realizan en el módulo de roles y usuarios han de hacerse autenticados contra Keycloak, para ello es necesario obtener un token JWT y usarlo en la cabecera 'Authorization' de las peticiones GraphQL que se vayan a hacer. Otra forma de hacerlo es creando un script que se lance antes de la petición usando la opción "Pre-request Editor" que nos facilita Altair. Se adjunta ejemplo en la siguiente plantilla:
Plantilla de ejemplo de script |
---|
const nowInSeconds = () => Date.now() / 1000;
const tokenExpiry = localStorage.getItem("token_expiry") || 0;
if (nowInSeconds() >= Number(tokenExpiry)) {
// If the token expiry time has passed, fetch a new token from your auth server again (take note of the await)
const user_name = 'USUARIO_VALIDO_KEYCLOAK'
const user_password = 'PASSWORD_USUARIO_VALIDO_KEYCLOAK'
bodyString = 'grant_type=password&scope=openid&username='+user_name+'&password='+user_password
const res2 = await altair.helpers.request('POST', 'https://dev.connectedassets.onesait.com/auth/realms/onesaitplatform/protocol/openid-connect/token',{
'body': bodyString,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic CODIFICACION_BASE_64_CLIENTID_Y_SECRETID'
}
});
const access_token=res2['access_token']
localStorage.setItem("token", access_token);
localStorage.setItem("token_expiry", nowInSeconds() + res2["expires_in"]);
}
// Retrieve the token from localStorage
const token = localStorage.getItem("token");
altair.helpers.setEnvironment('access_token', token);
|
Como podemos observar hay algunas variables a rellenar, que son:
USUARIO_VALIDO_KEYCLOAK: usuario válido en Keycloak. Ejemplo: transversal
PASSWORD_USUARIO_VALIDO_KEYCLOAK: contraseña del usuario. Ejemplo: ***********
CODIFICACION_BASE_64_CLIENTID_Y_SECRETID: clientId:secretId del Realm de Keycloak codificadios en Base64. Cadena válida: VXNlclJvbGU6b25lc2FpdHBsYXRmb3Jt
Y por último añadir la cabecera usando la variable en la que guardamos el token JWT con el script anterior:
Hay que tener en cuenta también que en la primera ejecución de Altair es posible que haya definida una variable 'undefined'. Es necesario eliminarla para poder hacer peticiones.
Consideraciones
Cuando se usa la documentación con Altair es posible, a través de un simple click, desplazar la petición a la columna correspondiente como puede verse en la siguiente imagen.
En algunas peticiones como la anterior aparecen varios campos en rojo, que son campos que no están contemplados como devolución. Estos campos son necesarios eliminarlos para poder realizar la petición correctamente.
Tambien se puede observar que existe un argumento llamado input, y se trata de un argumento con varios campos. Si se hace click sobre él se puede ver más en detalle como se debe rellenar, como se puede observar en la siguiente imagen.
Una vez esté todo completado simplemente habría que lanzar la petición por medio de 'Send Request'.
Resumen de operaciones
En esta sección se comentarán las principales operaciones a buscar en la documentación para asi simplificar la integración con roles y usuarios.
Producto
Operación | Nombre de operación en GraphQL |
Obtener todos los productos | products |
Obtener producto | product |
Crear producto | createProduct |
Editar producto | updateProduct |
Eliminar producto | deleteProduct |
Proyecto
Operación | Nombre de operación en GraphQL |
Obtener todos los proyectos | projects |
Obtener proyecto | project |
Crear proyecto | createProject |
Editar proyecto | updateProject |
Eliminar proyecto | deleteProject |
Módulo
Operación | Nombre de operación en GraphQL |
Obtener todos los módulos | Producto: modulesProduct Proyecto: modulesProject |
Crear módulo | Producto: createModuleProduct Proyecto: createModuleProject |
Editar módulo | updateModule |
Obtener todos los submódulos | Producto: submodulesProduct Proyecto: submodulesProject |
Crear submódulo | Producto: createSubmoduleProduct Proyecto: createSubmoduleProject |
Eliminar módulo | deleteModule |
Eliminar submódulo | deletesubmodule |
Permisos
Operación | Nombre de operación en GraphQL |
Obtener permisos |
|
Crear permiso | createPermission |
Editar permiso | updatePermission |
Eliminar permiso | deletePermission |
Rol
Operación | Nombre de operación en GraphQL |
Obtener roles | Producto: rolesProduct Proyecto: rolesProject |
Obtener rol | role |
Crear rol | Producto: createRoleProduct Proyecto: createRoleProject |
Editar rol | updateRole |
Añadir permisos a un rol | roleAddPermissions |
Editar permisos de un rol | roleSetPermissions |
Borrar permisos de un rol | roleDeletePermissions |
Eliminar rol | deleteRole |
Usuarios
Operación | Nombre de operación en GraphQL |
Obtener usuarios | users |
Obtener usuario | user |
Crear usuario | createUser |
Editar usuario | updateUser |
Borrar usuario | deleteUser |
Integración con la librería de permisos
Roles & Usuarios dispone de gestión de permisos sobre los roles, y es posible integrar una librería para autorizar las peticiones sobre los permisos asignados a determinados roles. Para ello se hace uso de la librería que interpreta el token JWT generado y obtiene y analiza los permisos sobre el proyecto.
Actualmente la librería de permisos está en su versión más temprana: 0.0.1-SNAPSHOT. Para integrarla dentro de nuestras dependencias de maven simplemente habría que incluir lo siguiente:
Dependencia de maven |
---|
<dependencies>
...
<dependency>
<groupId>com.minsait.onesait.architecture</groupId>
<artifactId>onesait-multi-user-role-lib</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
...
</dependencies> |
Uso de la librería
Se integra directamente con Spring Security a través de su anotación @PreAuthorize, a continuación se muestran los distintos usos implementados en la librería.
Método | Descripción | Ejemplo de uso |
existsModule(String) | Verifica si el token contiene el módulo indicado | @PreAuthorize("existsModule('m_nombreModulo')") |
existsAnyModule(String, String...) | Verifica si el token contiene alguno de los módulos indicados | @PreAuthorize("existsAnyModule('m_nombreModulo1','m_nombreModulo2')") |
existsAllModules(String, String...) | Verifica que el token contenga todos los módulos indicados | @PreAuthorize("existsAllModules('m_nombreModulo1','m_nombreModulo2')") |
existsSubmodule(String) | Verifica si el token contiene el submódulo indicado | @PreAuthorize("existsSubmodule('m_nombreModulo/m_nombreSubmodulo')") |
existsAnySubmodule(String, String...) | Verifica si el token contiene alguno de los submódulos indicados | @PreAuthorize("existsAnySubmodule('m_nombreModulo1/m_nombreSubmodulo1','m_nombreModulo2/m_nombreSubmodulo2')") |
existsAllModules(String, String...) | Verifica que el token contenga todos los módulos indicados | @PreAuthorize("existsAllSubmodules('m_nombreModulo1/m_nombreSubmodulo1','m_nombreModulo2/m_nombreSubmodulo2')") |
hasRootPermission(String) | Verifica que el token contenga el permiso a nivel general | @PreAuthorize("hasRootPermission('p_ADMIN')") |
hasAnyRootPermission(String, String...) | Verifica que el token contenga alguno de los permisos indicados a nivel general | @PreAuthorize("hasAnyRootPermission('p_EDIT','p_VIEW')") |
hasAllRootPermissions(String, String...) | Verifica que el token contenga alguno de los permisos indicados a nivel general | @PreAuthorize("hasAllRootPermissions('p_EDIT','p_VIEW')") |
hasPathPermission(String) | Verifica que el token contenga el permiso indicado a nivel de módulo o submódulo | @PreAuthorize("hasPathPermission('m_Assets/m_Enumerations/p_VIEW')") |
hasAnyPathPermissions(String, String...) | Verifica que el token contenga alguno de los permisos indicados a nivel de módulo o submódulo | @PreAuthorize("hasAnyPathPermissions('m_Assets/m_Enumerations/p_VIEW', 'm_Assets/m_Enumerations/p_EDIT')") |
hasAllPathPermissions(String, String...) | Verifica que el token contenga todos los permisos indicados a nivel de módulo o submódulo | @PreAuthorize("hasAllPathPermissions('m_Assets/m_Enumerations/p_VIEW', 'm_Assets/m_Enumerations/p_EDIT')") |
hasLevelPermission(String, String) | Verifica que el token contenga el permiso indicado dentro del módulo o submódulo indicado | @PreAuthorize("hasLevelPermission('m_Assets/m_Enumerations','p_VIEW')") |
hasAnyLevelPermission(String, String, String...) | Verifica que el token contenga alguno de los permisos indicados dentro del módulo o submódulo indicado | @PreAuthorize("hasAnyLevelPermission('m_Assets/m_Enumerations','p_VIEW', 'p_EDIT')") |
hasAllLevelPermissions(String, String, String...) | Verifica que el token contenga todos los permisos indicados dentro del módulo o submódulo indicado | @PreAuthorize("hasAllLevelPermission('m_Assets/m_Enumerations','p_VIEW', 'p_EDIT')") |