У меня есть хранимая процедура в SQL Server 2019. Она усекает промежуточную таблицу, а затем вставляет данные. Я предоставил User1
EXECUTE
разрешения для этой хранимой процедуры usp_insert_data
.
Однако когда я выполняю хранимую процедуру, она терпит неудачу из-за TRUNCATE
. Если я удалю TRUNCATE
, все будет работать нормально. Насколько я понимаю, TRUNCATE
могут создавать только пользователи с определенными привилегиями, которые я не хочу предоставлять User1
.
Я создал другого пользователя PowerUser
, которому дал ALTER
разрешения на доступ к таблице tbl_data
, а затем включил следующий код в свою хранимую процедуру:
EXECUTE AS USER = N'PowerUser';
TRUNCATE TABLE [dbo].[tbl_data];
REVERT;
Моя хранимая процедура теперь выглядит так:
ALTER PROCEDURE [dbo].[usp_insert_data]
@id bigint,
@utc datetime,
@latitude decimal(19,15),
@longitude decimal(19,15)
AS
SET NOCOUNT ON;
BEGIN
EXECUTE AS USER = N'PowerUser';
TRUNCATE TABLE [dbo].[tbl_data];
REVERT;
INSERT INTO [tbl_data] (plot_id, utc, gmt,
latitude, longitude)
VALUES (@plot_id, @utc,
@utc AT TIME ZONE 'UTC' AT TIME ZONE 'GMT Standard Time',
@latitude, @longitude)
END;
Но я все еще получаю следующую ошибку:
Сообщение 1088, уровень 16, состояние 7, процедура dbo.usp_insert_data, строка 7 [строка запуска пакета 2]
Невозможно найти объект «tbl_data», поскольку он не существует или у вас нет разрешений.
Чтобы разрешить EXECUTE AS
PowerUser User1
, мне нужно запустить этот код:
GRANT IMPERSONATE ON USER:: [PowerUser] TO [User1]
что означало бы, что пользователь может выдавать себя за другое лицо по своему желанию или я делаю что-то не так?
Спасибо
Чтобы использовать оператор EXECUTE AS
в хранимой процедуре, USER
/LOGIN
требуется явное разрешение на олицетворение этого USER
/LOGIN
. Вместо этого вам следует определить EXECUTE AS
в предложении WITH
процедуры и определить PowerUser
USER
в этом предложении. Например:
--Create a sample table
CREATE TABLE dbo.SomeTable (SomeID int IDENTITY CONSTRAINT PK_SomeTable PRIMARY KEY,
SomeString varchar(10),
SomeDate date,
SomeInt int,
TheUser sysname DEFAULT USER_NAME());
GO
--Create the sample user and a power user
CREATE USER SomeUser WITHOUT LOGIN;
CREATE USER PowerUser WITHOUT LOGIN;
GO
GRANT ALTER, INSERT ON dbo.SomeTable TO PowerUser; --Give the PowerUser the ability to ALTER and INSERT the sample table
GO
--Create the sample procedure that TRUNCATEs and the INSERTs into the table
CREATE OR ALTER PROC dbo.SomeProc @SomeString varchar(10),
@SomeDate date,
@SomeInt int
WITH EXECUTE AS 'PowerUser' AS --now the proc will execute as the PowerUser
BEGIN
SET NOCOUNT ON;
TRUNCATE TABLE dbo.SomeTable;
INSERT INTO dbo.SomeTable (SomeString, SomeDate, SomeInt)
VALUES(@SomeString, @SomeDate, @SomeInt);
END;
GO
--Give the sample user permission to execute the proc
GRANT EXECUTE ON dbo.SomeProc TO SomeUser;
GO
--Impersonate our sample user
EXECUTE AS USER = N'SomeUser';
GO
--Run the proc
EXEC dbo.SomeProc 'abc', '20240621','123';
GO
--Run the proc again (this'll delete the original row)
EXEC dbo.SomeProc 'def', '20240622','456';
GO
--Back to "us"
REVERT;
GO
--Check the data is the second data set, but will have an ID of 1, not 2.
SELECT *
FROM dbo.SomeTable;
GO
--Clean up
DROP USER SomeUser;
DROP PROC dbo.SomeProc;
DROP TABLE dbo.SomeTable;
Если вы хотите вернуться к вызывающему пользователю в рамках процедуры, вы можете использовать EXECUTE AS CALLER
:
CREATE OR ALTER PROC dbo.SomeProc @SomeString varchar(10),
@SomeDate date,
@SomeInt int
WITH EXECUTE AS 'PowerUser' AS --now the proc will execute as the PowerUser
BEGIN
SET NOCOUNT ON;
TRUNCATE TABLE dbo.SomeTable;
EXECUTE AS CALLER; --Now we're whoever ran the EXEC
INSERT INTO dbo.SomeTable (SomeString, SomeDate, SomeInt)
VALUES(@SomeString, @SomeDate, @SomeInt);
REVERT; --Isn't really needed, but to be "safe"
END;
Сейчас я не могу проверить, но помню, что OWNER
не предоставил необходимые разрешения TRUNCATE
здесь, @DerU .
Если владелец sp также является владельцем базы данных, то почти наверняка у него есть разрешение ALTER (необходимое для TRUNCATE) на таблицу (в той же базе данных). Если это не владелец базы данных, нам нужно убедиться, что пользователь, владеющий sp, также имеет разрешения ALTER для таблицы. Лучше всего создать отдельного пользователя («PowerUser») со всеми конкретными разрешениями и только с ними.
Мне нравится этот тестовый скрипт, он показывает весь принцип. Будет ли «С ВЫПОЛНЕНИЕМ КАК ВЛАДЕЛЬЦА» полезной и безопасной альтернативой? Или мы всегда должны создавать пользователя «PowerUser» с разрешениями, ограниченными конкретным конкретным использованием?