给出一个简化的存储过程
CREATE OR ALTER PROCEDURE [FooSchema].[Foo]
AS
SELECT
B.*,
FROM [BarSchema].[Bar] AS B
WHERE [...]
在FooSchema而不是BarSchema上向用户授予EXEC后,该存储过程将失败,并显示以下消息
The SELECT permission was denied on the object 'Bar',
有没有一种方法可以使用户访问[FooSchema]。[Foo]而不会暴露[BarSchema]。[Bar]的整个数据集是因为存储过程已经过滤掉了与此用户相关的数据。
答案 0 :(得分:3)
最简单的选择是使用[WITH EXECUTE AS]
语句,其中指定的用户名具有相关对象所需的确切权限。
CREATE OR ALTER PROCEDURE [FooSchema].[Foo]
WITH EXECUTE AS '<username>'
AS
SELECT
B.*,
FROM [BarSchema].[Bar] AS B
WHERE [...]
答案 1 :(得分:2)
如果两个模式都由同一用户拥有,则将应用常规的所有权链接,并且对proc具有EXECUTE
权限的用户不需要对基础对象的权限。用户将只能使用存储过程返回的数据,并且除非您明确授予他们这样做的权限,否则将无法对表执行临时查询。
例如:
CREATE USER SchemaOwner WITHOUT LOGIN;
ALTER AUTHORIZATION ON SCHEMA::FooSchema TO SchemaOwner;
ALTER AUTHORIZATION ON SCHEMA::BarSchema TO SchemaOwner;
另一种仅在模块范围内提供附加权限的方法是使用模块签名。
CREATE CERTIFICATE FooUserCertificate
ENCRYPTION BY PASSWORD = '0bfuscatedPassword'
WITH SUBJECT = 'Allow access to bar table';
CREATE USER FooUser FROM CERTIFICATE FooUserCertificate;
GRANT SELECT ON BarSchema.Bar TO FooUser;
ADD SIGNATURE TO FooSchema.Foo BY CERTIFICATE FooUserCertificate
WITH PASSWORD = '0bfuscatedPassword';
ALTER CERTIFICATE FooUserCertificate REMOVE PRIVATE KEY;
GO
尽管更为复杂,但模块签名优于EXECUTE AS
的优点在于,原始调用者的身份在执行期间得以保留,而不会在当前数据库中进行沙箱处理。这对于审核和跨数据库访问很有用。有关更多信息,请参见this article。