Как узнать, что пользователь выполняет действие по удалению таблицы аудита при использовании общего входа?

8

Исходная информация:

  • Я создаю коллекцию таблиц аудита для отслеживания обновлений и удалений в наборе таблиц данных для моего приложения.
  • Аудиторские записи создаются с помощью триггеров.
  • DML в базе данных моего приложения обычно поступает от имени входа, которое служба использует для входа в базу данных. Из-за этого, я думаю, что результат SYSTEM_USERвсегда будет одинаковым при вызове в триггере.
  • Мое приложение не хранит пользовательские данные в настоящее время, хотя UserIdему каждый раз передается строка (выполняется исключительно в хранимых процедурах).

Проблема, с которой я столкнулся, заключается в том, что когда пользователь удаляет запись, я хочу знать, кто это сделал. Поскольку это будет сделано при том же входе в систему, я не хочу видеть, что все действия были выполнены службой, я хочу видеть, какой пользователь это сделал. Это не проблема для обновления, потому что у нас есть ModifiedByстолбцы, которые будут обновляться через отправленные UserIdобновления.

Вопрос заключается в следующем: есть ли способ установить SYSTEM_USERили иным образом получить информацию о пользователе в триггер при запуске удаления?

«Лучшая» идея, которая у меня есть сейчас, хотя я не уверен, что это хорошая идея, заключается в том, что в сервисе я проверяю, находится ли текущий пользователь UserIdв базе данных как пользователь, и, если нет, создает пользователя. объект для них. Затем запустите хранимые процедуры с помощью EXECUTE AS User = @UserId. Затем, когда DML будет выполнен в хранимой процедуре и триггер срабатывает, SYSTEM_USERследует вернуть пользователя из EXECUTE AS.

Джереми Придемор
источник
2
@RBarryYoung И этот механизм является предметом вопроса. Мой сервис входит в мою базу данных, выполняя действия для того, кто его вызвал, и у меня есть доступный идентификатор пользователя. Мне нужно выяснить, как записать этот UserId в случае удаления.
Джереми Придемор
Справедливо, я должен был прочитать ваш вопрос более тщательно. Я думаю, что у меня есть ответ на этот вопрос, но я не смогу опубликовать его до позднего вечера.
RBarryYoung

Ответы:

4

Хотя использование EXECUTE AS User = @UserIdможет быть вашим лучшим вариантом (в зависимости от других проблем), вот альтернативный подход:

В хранимых процедурах или в любое время сеанса SQL перед DELETEвыполнением выполните следующую команду:

SET CONTEXT_INFO @UserId

Затем в вашем триггере вы можете получить это значение с помощью

SELECT @var = CAST(CAST(CONTEXT_INFO() As Varbinary(4)) As Int)

Это имеет ряд недостатков, наиболее важным из которых является то, что вы не можете легко использовать CONTEXT_INFO для более чем одной вещи одновременно.

RBarryYoung
источник
Мы решили не иметь информации на данный момент. Если мы решим, что мы должны это сделать, я сначала попробую. Спасибо за идею.
Джереми Придемор
2

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

http://technet.microsoft.com/en-us/library/ms189492.aspx

«Эта функция может быть полезна при проверке подлинности исходного соединительного контекста. В то время как функции, такие как SESSION_USER и CURRENT_USER, возвращают текущий исполняемый контекст, ORIGINAL_LOGIN возвращает идентификатор входа в систему, который первым подключился к экземпляру SQL Server в этом сеансе».

ДКП
источник
Это аккуратная функция, спасибо, что подняли ее. Я почти уверен, что когда у меня запущен сервис, который каждый раз обращается к базе данных с одним и тем же логином сервера, тогда ORIGINAL_LOGIN () всегда возвращает пользователя, которого использует сервис. Это звучит правильно для вас?
Джереми Придемор,
Да, если вы проходите через учетную запись службы, чтобы установить соединение с базой данных, тогда ORIGINAL_LOGIN () будет службой. Если вы измените контекст после подключения к базе данных от себя, тогда ORIGINAL_LOGIN () должен быть вашим логином.
RLF
0

Вы также можете попробовать добавить Host_Nameв свои таблицы. Я обнаружил, что в тех случаях, когда у меня есть общая учетная запись, я обычно могу отследить человека по имени его машины, поскольку 95% времени человек работает со своей собственной машины. Это не всегда работает, но это может быть полезной дополнительной информацией.

SELECT host_name FROM sys.dm_exec_sessions WHERE session_id = @@SPID

К сожалению, это не сработает, если вы работаете с веб-приложением, хостом которого всегда будет само веб-приложение, но, возможно, стоит попробовать.

Кеннет Фишер
источник