Какова наилучшая практика для получения текущего имени пользователя на уровне доступа к данным?

StackOverflow https://stackoverflow.com/questions/1980814

  •  22-09-2019
  •  | 
  •  

Вопрос

Недавно мы добавили аудит в нашу базу данных.Коллега реализовал это с помощью триггеров и попросил меня вызвать хранимую процедуру при входе на веб-сайт.Хранимая процедура вставляет текущее имя пользователя и текущий идентификатор сеанса oracle в таблицу, чтобы триггер мог сопоставить идентификатор сеанса с именем пользователя.Проблема в том (или была), что он предполагал, что интернет-сеанс пользователя сопоставлен сеансу базы данных.Это не так, и мы используем пул подключений, поэтому идентификаторы сеанса oracle могут быть сопоставлены многим пользователям, не обязательно пользователю, вошедшему в систему в этом сеансе.Итак, я создал служебный метод на своем уровне доступа к данным, который вызывает его процедуру при каждой вставке, обновлении и удалении (гарантируя, что это происходит в одной транзакции):

/// <summary>
/// Performs an insert, update or delete against the database
/// </summary>
/// <param name="transaction"></param>
/// <param name="command">The command.</param>
/// <param name="transaction">A transaction, can be null. 
/// No override provided without a transaction, to remind developer to always consider transaction for inserts, updates and deletes</param>
/// <returns>The number of rows affected by the operation</returns>
public static int InsertUpdateDelete(OracleCommand command, OracleTransaction transaction)
{
  if (command == null)
    throw new ArgumentNullException("command", "command is null.");

  OracleConnection connection = null;
  bool doCommit = false;
  try
  {
    if (transaction == null)
    {
      //We always need a transaction for the audit insert
      connection = GetOpenConnection();
      transaction = connection.BeginTransaction();
      doCommit = true;
    }

    command.Transaction = transaction;
    command.Connection = transaction.Connection;

    //TODO HttpContext requires that presentation layer is a website. So this call should NOT be in the data access layer.
    string username = HttpContext.Current.User.Identity.Name;
    if (!String.IsNullOrEmpty(username))
      pInsertCurrentUserForAudit(username, command.Transaction);

    int recordsAffected = command.ExecuteNonQuery();

    if (doCommit)
      transaction.Commit();

    return recordsAffected;
  }
  finally
  {
    if (doCommit)
    {
      if (transaction != null)
        transaction.Dispose();
      if (connection != null)
        connection.Dispose();
    }
  }
}

Это работает, и теперь аудит работает так, как требуется.Однако мне не нравится вызов HttpContext:

string username = HttpContext.Current.User.Identity.Name;

Это был самый быстрый способ реализации задачи, но я не думаю, что это должно быть на уровне доступа к данным.Что, если в какой-то неизвестный момент в будущем я захочу получить доступ к базе данных с помощью приложения forms?Получу ли я сообщение об ошибке при доступе к HttpContext?Есть ли лучший способ получить доступ к имени пользователя, который должным образом разделяет проблемы?Передача имени пользователя в качестве параметра для каждой вставки, обновления и удаления - это вариант, но это будет длительная задача, и мне было интересно, есть ли более элегантный способ сделать это.

Это было полезно?

Решение

То, что вы сделали, определенно не самый лучший подход (как вы изложили выше в своем вопросе) Это одна из тех вещей, которые называются сквозной проблемой - другие - это такие вещи, как ведение журнала и т.д.)

Один из используемых подходов заключается в том , чтобы передать контекстный объект это реализует функциональность для всех таких сквозных задач, так что каждый метод на каждом уровне не нужно модифицировать для передачи данных, необходимых для реализации желаемой функциональности.

В противном случае, как вы предлагаете, вам придется передавать имя пользователя на уровень данных с более высокого уровня стека в каждом методе, которому это необходимо.Если возможно, одной из альтернатив является внедрение базового класса для всех таких методов (всех методов уровня данных) и помещение этого метода в этот базовый класс...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top