При работе с SQL Server часто возникают ситуации, когда вам необходимо отслеживать информацию о пользователе, который выполнил определенное действие, например, вставку записи в таблицу. В таких случаях вы можете захотеть включить столбцы, такие как InsertDate и InsertBy, в вашу таблицу. В то время как InsertDate относительно просто обрабатывается с помощью функций, таких как GETDATE() или GETUTCDATE(), определение значения для InsertBy может быть более сложным.
В этой статье мы рассмотрим различные пользовательские функции в SQL Server, которые могут быть использованы для получения имени входа пользователя, который инициировал действие, независимо от имперсонации. Мы также обсудим различия между этими функциями и их практическое применение.
Вот некоторые из пользовательских функций, которые мы рассмотрим:
- ORIGINAL_LOGIN()
- CURRENT_USER
- SESSION_USER
- SYSTEM_USER
- USER_NAME()
- USER
- SUSER_SNAME()
- SUSER_NAME()
Чтобы лучше понять результаты каждой функции, мы проведем некоторые тесты. Давайте начнем с создания пары входов и связанных пользователей. Мы также предоставим некоторые высокоуровневые разрешения этим принципалам для тестирования.
-- Выполняется с пользователем с расширенными разрешениями.
USE master;
GO
CREATE LOGIN MyLogin WITH PASSWORD = 'MyLogin', CHECK_POLICY = OFF;
EXEC sp_addsrvrolemember 'MyLogin','sysadmin'
CREATE LOGIN MyImpLogin WITH Password = 'MyImpLogin',
CHECK_POLICY = OFF;
GO
USE Test;
GO
CREATE USER MyUser FROM LOGIN MyLogin;
CREATE USER MyImpUser FROM LOGIN MyImpLogin;
EXEC sp_addrolemember 'db_owner','MyImpUser';
GO
Теперь давайте создадим базовую таблицу со значениями для каждой пользовательской функции. Это поможет нам понять возвращаемые каждой функцией типы данных.
-- Выполняется как MyLogin/MyUser
USE Test;
GO
SELECT
'Baseline ' AS TestName,
ORIGINAL_LOGIN() AS [ORIGINAL_LOGIN],
CURRENT_USER AS [CURRENT_USER],
SESSION_USER AS [SESSION_USER],
SYSTEM_USER AS [SYSTEM_USER],
USER_NAME() AS [USER_NAME],
USER AS [USER],
SUSER_SNAME() AS [SUSER_SNAME],
SUSER_NAME() AS [SUSER_NAME]
INTO UserTest;
Мы также проведем дополнительные тесты, удалив привилегии sysadmin у MyLogin и предоставив разрешения на чтение/запись и выполнение MyUser. Затем мы будем использовать оператор EXECUTE AS для изменения текущего контекста на MyImpLogin и MyImpUser соответственно.
Наконец, мы протестируем клаузу EXECUTE AS OWNER хранимой процедуры, чтобы увидеть, как это влияет на пользовательские функции.
После выполнения этих тестов мы можем проанализировать результаты. Во-первых, мы замечаем, что все пользовательские функции возвращают значения типа nvarchar(128), за исключением ORIGINAL_LOGIN(), которая возвращает nvarchar(4000). Независимо от типа данных, ORIGINAL_LOGIN() всегда предоставляет фактическое имя входа, что делает ее надежным выбором для старых столбцов, таких как InsertBy.
При использовании имперсонации с помощью EXECUTE AS большинство пользовательских функций возвращают имперсонированный вход/пользователь, за исключением ORIGINAL_LOGIN(), которая остается неизменной. Кроме того, при использовании EXECUTE AS OWNER в хранимой процедуре все пользовательские функции, кроме ORIGINAL_LOGIN(), возвращают dbo и sa, владельца базы данных.
Исходя из этих результатов, мы можем заключить, что ORIGINAL_LOGIN() – это единственная функция, которая всегда возвращает фактическое имя входа, независимо от имперсонации или контекста владения.
Не забудьте очистить пользователей и входы после выполнения этих тестов:
-- Выполняется с пользователем с расширенными разрешениями.
USE master;
DROP LOGIN MyLogin;
DROP LOGIN MyImpLogin;
USE Test;
DROP USER MyUser;
DROP USER MyImpUser;
DROP TABLE UserTest;
В заключение, понимание различных пользовательских функций в SQL Server является важным при работе со старыми столбцами или отслеживании информации о пользователе. Используя ORIGINAL_LOGIN(), вы можете обеспечить последовательные и точные результаты, независимо от имперсонации или контекста владения.
Спасибо за прочтение этой статьи. Следите за новыми советами и трюками по SQL Server!