Это легко сделать очень безопасным способом, используя подпись модулей. Это будет похоже на следующие два моих ответа, также здесь, на DBA.StackExchange, в которых приведены примеры того, как это сделать:
Безопасность хранимых процедур с помощью execute as, запросов к базе данных и подписи модуля
Разрешения в триггерах при использовании кросс-сертификатов базы данных
Разница для этого конкретного вопроса заключается в том, что он имеет дело с представлением, и представления не могут быть подписаны. Таким образом, вам нужно будет изменить представление в табличную функцию с множеством операторов (TVF), так как они могут быть подписаны и доступны так же, как представление (ну, для SELECT
доступа).
В следующем примере кода показано выполнение именно того, что запрашивается в вопросе, в том, что «Ограниченный пользователь» для входа / пользователя имеет доступ только к «DatabaseA» и все же может получать данные из «DatabaseB». Это работает только путем выбора из этого одного TVF , и только потому, что он подписан.
Для реализации этого типа доступа к нескольким базам данных при использовании представления и без предоставления Пользователю каких-либо дополнительных разрешений потребуется включение цепочки владения несколькими базами данных. Это гораздо менее безопасно, потому что он полностью открыт для всех объектов между обеими базами данных (он не может быть ограничен определенными объектами и / или пользователями). Подписание модуля позволяет только этому одному TVF иметь доступ между БД (у пользователя нет разрешения, у TVF есть), а у пользователей, которые не могут SELECT
из TVF вообще не иметь доступа к базе данныхB.
USE [master];
CREATE LOGIN [RestrictedUser] WITH PASSWORD = 'No way? Yes way!';
GO
---
USE [DatabaseA];
CREATE USER [RestrictedUser] FOR LOGIN [RestrictedUser];
GO
CREATE FUNCTION dbo.DataFromOtherDB()
RETURNS @Results TABLE ([SomeValue] INT)
AS
BEGIN
INSERT INTO @Results ([SomeValue])
SELECT [SomeValue]
FROM DatabaseB.dbo.LotsOfValues;
RETURN;
END;
GO
GRANT SELECT ON dbo.[DataFromOtherDB] TO [RestrictedUser];
GO
---
USE [DatabaseB];
CREATE TABLE dbo.[LotsOfValues]
(
[LotsOfValuesID] INT IDENTITY(1, 1) NOT NULL
CONSTRAINT [PK_LotsOfValues] PRIMARY KEY,
[SomeValue] INT
);
INSERT INTO dbo.[LotsOfValues] VALUES
(1), (10), (100), (1000);
GO
---
USE [DatabaseA];
SELECT * FROM dbo.[DataFromOtherDB]();
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
REVERT;
Все вышеперечисленные шаги воссоздают текущую ситуацию: пользователь имеет доступ к базе данных DatabaseA, имеет разрешение на взаимодействие с объектом в базе данных DatabaseA, но получает ошибку из-за того, что объект в базе данных DatabaseA получает доступ к чему-либо в базе данных DatabaseB, к которой у пользователя нет никакого доступа.
Шаги ниже настраивают пение модуля. Это делает следующее:
- создает сертификат в базе данных
- Подписывает TVF с сертификатом
- Копирует сертификат (без закрытого ключа) в базу данных B
- Создает пользователя в базе данныхB из сертификата
- Предоставляет
SELECT
разрешение на Таблицу в базе данныхB Пользователю на основе сертификатов
Настройка подписи модуля:
CREATE CERTIFICATE [AccessOtherDB]
ENCRYPTION BY PASSWORD = 'SomePassword'
WITH SUBJECT = 'Used for accessing other DB',
EXPIRY_DATE = '2099-12-31';
ADD SIGNATURE
TO dbo.[DataFromOtherDB]
BY CERTIFICATE [AccessOtherDB]
WITH PASSWORD = 'SomePassword';
---
DECLARE @CertificatePublicKey NVARCHAR(MAX) =
CONVERT(NVARCHAR(MAX), CERTENCODED(CERT_ID(N'AccessOtherDB')), 1);
SELECT @CertificatePublicKey AS [Cert / PublicKey]; -- debug
EXEC (N'USE [DatabaseB];
CREATE CERTIFICATE [AccessOtherDB] FROM BINARY = ' + @CertificatePublicKey + N';');
---
EXEC (N'
USE [DatabaseB];
CREATE USER [AccessOtherDbUser] FROM CERTIFICATE [AccessOtherDB];
GRANT SELECT ON dbo.[LotsOfValues] TO [AccessOtherDbUser];
');
---
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
-- Success!!
SELECT * FROM [DatabaseB].[dbo].[LotsOfValues];
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
REVERT;
Если доступ по какой-либо причине необходим через просмотр, тогда вы можете просто создать вид, который выбирается из TVF, показанного выше. И, в этой ситуации, SELECT
доступ не должен быть предоставлен для TVF, только для просмотра, как показано ниже:
GO
CREATE VIEW dbo.[DataFromTVF]
AS
SELECT [SomeValue]
FROM dbo.DataFromOtherDB();
GO
-- Remove direct access to the TVF as it is no longer needed:
REVOKE SELECT ON dbo.[DataFromOtherDB] FROM [RestrictedUser];
GRANT SELECT ON dbo.[DataFromTVF] TO [RestrictedUser];
А теперь, чтобы проверить это:
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
/*
Msg 229, Level 14, State 5, Line XXXXX
The SELECT permission was denied on the object 'DataFromOtherDB',
database 'DatabaseA', schema 'dbo'.
*/
SELECT * FROM [OwnershipChaining].[dbo].[LotsOfValues];
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
SELECT * FROM dbo.[DataFromTVF];
-- Success!!
REVERT;
Для получения дополнительной информации о подписи модулей, пожалуйста, посетите: https://ModuleSigning.Info/