1

我正在使用一个具有大约 150 个服务的 spring 应用程序,因此我需要审核每个服务的每个 http 事件请求(发布、放置和删除),其中的审核数据应该是发出 http 请求的用户它必须存储在数据库中。

为了实现这一点,在 Spring 方面,我创建了一个 http 拦截器来获取用户并将其存储在使用 java 创建的 Postgres Temp 表中。

// The Interceptor

@Component
public class AuditHttpRequestHandlerInterceptor implements HandlerInterceptor {
    @Inject private AuditBasicAuthExtractor auditBasicAuthExtractor;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            String user = auditBasicAuthExtractor.getUser();
            auditBasicAuthExtractor.addTempTable(user);
        } catch (Exception ex) {
            LOGGER.error("", ex);
        }

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,  @Nullable Exception ex) throws Exception {
    }
}

// Temp Table Creation

    private void createNewTempTable(DataSource dataSource, String tempTableName, List<String> columns) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = dataSource.getConnection();
            String sqlStatement = "CREATE TEMP TABLE IF NOT EXISTS ".concat(tempTableName).concat(" ( ");//here I create the temp table
            for (String column:
                 columns) {
                sqlStatement = sqlStatement.concat(column);// one of the columns is the user
            }
            sqlStatement = sqlStatement.concat(")");
            preparedStatement = connection.prepareStatement(sqlStatement);
            preparedStatement.executeUpdate();
        } catch (SQLException throwables) {
            LOGGER.error("SQLException ", throwables);
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException throwables) {
                LOGGER.error("SQLException", throwables);
            }
        }
    }

在 Postgres 上,我创建了一个插入、更新和删除后触发器,该触发器参考临时表以获取相应的用户,之后触发器将此用户存储在审计表中(在父审计表中,我存储用户和子审计表我存储修改后的列名和旧值和新值)。

// Piece of code of the trigger

CREATE OR REPLACE FUNCTION audit_changes() RETURNS TRIGGER AS $$
DECLARE
BEGIN
  IF EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp_user_table') THEN
    SELECT user_id INTO user_name FROM cloud_context; --here fetches the user
  END IF;
END;
$$ LANGUAGE plpgsql;

这适用于 2 或 3 个并发的不同用户(触发器正确获取每个用户)。

但是假设我们有 50 个不同的并发用户同时发出请求。在这种情况下,临时表存储 50 个不同的行(每个用户一个),因此在这种情况下,触发器无法识别哪个用户发出了相应的请求。

我想在拦截器中包含一个唯一标识符,目的是触发器可以通过该标识符选择用户,但我不知道如何在拦截器和触发器之间共享该 ID。

我将不胜感激任何帮助或指导来解决这个问题,任何替代解决方案也会很好。

4

0 回答 0