出于安全原因,我们的数据被分成许多不同的数据库。 我在配置安全性时遇到问题,以至于受限制的登录可以通过函数调用从另一个数据库访问特定数据。
我创建了一个简单的场景,演示了以下问题:(以sa或其他管理员用户身份运行)
CREATE DATABASE Test1
GO
USE Test1
CREATE Login TestA WITH PASSWORD='changeme'
CREATE USER TestA FOR LOGIN TestA
GO
CREATE DATABASE Test2
GO
USE Test2
CREATE Login TestB WITH PASSWORD='changemealso'
CREATE USER TestB FOR LOGIN TestB
CREATE USER TestA FOR LOGIN TestA
GO
CREATE DATABASE Test3
GO
USE Test3
CREATE TABLE SomeTable (ID int identity(1,1) primary key, SomeColumn nvarchar(max))
INSERT INTO someTable Values ('hello'), ('world')
CREATE USER TestB FOR LOGIN TestB
GRANT SELECT ON SomeTable To TestB
USE Test2
GO
CREATE VIEW SomeTable AS SELECT * FROM Test3.dbo.SomeTable
GO
CREATE FUNCTION dbo.SomeFunction()
RETURNS nvarchar(max)
WITH EXECUTE AS 'TestB'
AS
BEGIN
RETURN (SELECT top 1 SomeColumn FROM SomeTable)
END
GO
GRANT EXEC ON dbo.SomeFunction to TestA
USE Test1
SELECT Test2.dbo.SomeFunction() -- this fails, even when logged in as sa. Interestingly though, it DOES return an empty result set - despite the error.
GO
use MASTER
DROP Database Test1
DROP Database Test2
DROP Database Test3
DROP Login TestA
DROP Login TestB
给出的错误是
The server principal "TestB" is not able to access the database "Test3" under the current security context.
由于用户TestB已明确授予对该数据库的访问权限,因此有点令我感到困惑。
这个想法是应用程序将作为用户TestA连接到Test1。它不能直接访问Test3中的表,但Test2上的函数将允许访问该数据的子集。
Test2和Test3是独立的数据库,原因与安全无关。
我错过了什么才能让这个查询有效?
SELECT Test2.dbo.SomeFunction()
更新:
我认为问题源于函数附加的EXECUTE AS
子句。看起来这只能指定用户,而不是登录。由于用户只与一个数据库相关联,因此使用EXECUTE AS
的任何内容都无法对任何其他数据库执行任何操作。
本文提出了一种可行的解决方法:http://blog.sqlxdetails.com/procedure-with-execute-as-login/但似乎非常复杂,我担心可能会出现意外的副作用。
有更好的解决方法吗?