martes, 20 de mayo de 2014

Auditoría de tablas mediante triggers con información sobre el usuario

Uno de los usos de los triggers puede ser el de auditar los cambios que se realizan en los datos de nuestras tablas. Entre la información que podríamos considerar relevante, se encuentra la del autor de dichos cambios. El problema es que, en el contexto de ejecución de un trigger, sólo podemos tener acceso al usuario de base de datos que realiza el cambio, por ejemplo usando una consulta como esta:
SELECT user
INTO vusuario
FROM dual;
 

Si nuestra aplicación gestiona sus propios usuarios (los cuales supongamos que se conectan a las aplicaciones mediante uno o varios esquemas de Oracle prefijados) no tendremos acceso al usuario real que realiza un cambio dentro del trigger puesto que estos no tienen parámetros. Hoy veremos cómo conseguir que en el contexto de un trigger podamos acceder de forma sencilla y eficiente a la información del usuario real (no el de base de datos) que está realizando un cambio en nuestra tabla y así podamos auditarlo.

Para empezar, necesitaremos desarrollar un paquete que gestione los usuarios que utilizan las aplicaciones. Debería tener al menos algo como esto:
CREATE OR REPLACE PACKAGE datos_usuario
AS

/*******************************************************************************
-- PROCEDURE set_usuarioTriggers
--
-- Descripción: establece la variable interna de usuario para usar en triggers
--
-- Entrada:    pe_usuario: usuario de la aplicación
--
------------------------------------------------------------------------------
******************************************************************************/
PROCEDURE set_usuarioTriggers(
    pe_usuario IN  VARCHAR2 -- 255
);

   
/******************************************************************************
-- FUNCTION get_usuarioTriggers
--
-- Descripción: establece la variable interna usuario para usar en triggers
--
-- Salida:      usuario actual de la aplicación
--
******************************************************************************/
FUNCTION get_usuarioTriggers RETURN VARCHAR2; -- 255



END datos_usuario;
/

CREATE OR REPLACE PACKAGE BODY datos_usuario
AS

-- Variable que contendrá el usuario para usar en triggers
-- Se debe inicializar cada vez que un usuario se conecta
-- A la base de datos desde una aplicación
usuarioTriggers    VARCHAR2(255);


PROCEDURE set_usuarioTriggers(pe_usuario  IN VARCHAR2) IS

BEGIN
    usuarioTriggers := pe_usuario;
END set_usuarioTriggers;


FUNCTION get_usuarioTriggers RETURN VARCHAR2 IS

BEGIN
    RETURN usuarioTriggers;
END get_usuarioTriggers;


END datos_usuario;
/
 

Al inicio de nuestras aplicaciones habrá que invocar la función  datos_usuario.set_usuarioTriggers pasándole como parámetro el usuario real que la está utilizando.

Para terminar, desde el trigger de auditoría tendremos acceso al valor de dicho usuario llamando a la función datos_usuario.get_usuarioTriggers. Por ejemplo, algo como esto:

CREATE OR REPLACE TRIGGER UPDATE_JOB_HISTORY
AFTER UPDATE OF job_id, department_id ON employees
FOR EACH ROW
BEGIN
    INSERT INTO job_history(
        employee_id, start_date, end_date,
        job_id, department_id, user_id, date_id)
    VALUES(
        :OLD.employee_id, :OLD.start_date, :OLD.end_date,
        OLD.job_id, :OLD.department_id, datos_usuario.get_usuarioTriggers, SYSDATE);
END;
/

2 comentarios:

  1. Hola Javier.
    buen ejemplo.
    Lo he usado aunque bastante información se puede sacar directamente desde la base de datos con
    nvl(sys_context('USERENV','HOST'),'SERVIDOR'),
    nvl(sys_context('USERENV','OS_USER'),'USUARIO')
    directamente en el trigger sin necesidad de modificar la pantalla ni implementar el paquete.
    gracias por compartir.
    saludos
    javier

    ResponderEliminar
  2. Pero lo que se obtiene con tu consulta es el usuario de la maquina, mas no el usuario que esta usando la aplicacion.

    ResponderEliminar