7

我创建了一个存储过程,它执行一系列需要特殊权限的操作,例如创建数据库、恢复数据库等。我创建了这个存储过程

execute as self

...使其作为 SA 运行。这是因为我想让没有任何权限的 SQL 用户能够仅运行我定义的这些命令。

但是当我运行这个存储过程时,我得到

The server principal "sa" is not able to access the database "model" under the current security context.

为什么SA无法访问模型数据库?实际上,我在 SA 下自己运行了存储过程中的代码,并且运行良好。

4

2 回答 2

9

在继续之前阅读使用 EXECUTE AS 扩展数据库模拟。

当使用 EXECUTE AS USER 语句模拟主体时,或使用 EXECUTE AS 子句在数据库范围的模块中模拟主体时,默认情况下模拟范围仅限于数据库。这意味着对数据库范围之外的对象的引用将返回错误。

您需要使用模块签名是一个例子。

于 2013-04-25T10:39:55.620 回答
0

对于其他来这里寻找此信息的人,这里是演示 OP(和我)想要什么的示例代码(基于上面 Remus 的优秀信息):

    -- how to sign a stored procedure so it can access other Databases on same server
    -- adapted from this very helpful article 
    -- http://rusanu.com/2006/03/01/signing-an-activated-procedure/

    USE [master]
    GO
    CREATE DATABASE TempDB1
    CREATE DATABASE OtherDB2
    GO
    USE TempDB1
    GO
    -- create a user for TempDB1
    CREATE USER [foo] WITHOUT LOGIN
    GO

    CREATE PROCEDURE TempDB1_SP 
    AS 
    BEGIN 
        CREATE TABLE OtherDB2.dbo.TestTable (ID int NULL)
        IF @@ERROR=0 PRINT 'Successfully created table.' 
    END
    GO

    GRANT EXECUTE ON dbo.TempDB1_SP TO [foo]
    GO

    EXECUTE AS User='foo'
        PRINT 'Try to run an SP that accesses another database:'
        EXECUTE dbo.TempDB1_SP
        GO
    REVERT

    -- Output: Msg 916, Level 14, State 1, Procedure TempDB1_SP, Line 5
    --   [Batch Start Line 14]
    -- The server principal "..." is not able to access the database 
    --    "OtherDB2" under the current security context.

    PRINT ''
    PRINT 'Fix: Try again with signed SP...'

    -- Create cert with private key to sign the SP with. 
    -- Password not important, will drop private key

    USE TempDB1
    GO
    -- create a self-signed cert
    CREATE CERTIFICATE [DB_Cert] 
        ENCRYPTION BY PASSWORD = 'Password1' 
        WITH SUBJECT = 'Signing for cross-DB SPs';
    -- Sign the procedure with the certificate’s private key
    ADD SIGNATURE TO OBJECT::[TempDB1_SP] 
        BY CERTIFICATE [DB_Cert] 
        WITH PASSWORD = 'Password1'
    -- Drop the private key. This way it cannot be used again to sign other procedures.
    ALTER CERTIFICATE [DB_Cert] REMOVE PRIVATE KEY
    -- Copy the public key part of the cert to [master] database 
    -- backup to a file and create cert from file in [master]
    BACKUP CERTIFICATE [DB_Cert] TO FILE = 'C:\Users\Public\DBCert.cer'

    USE [OtherDB2] -- or use [master] = all DBs on server accessible
    GO
    CREATE CERTIFICATE [DB_Cert] FROM FILE = 'C:\Users\Public\DBCert.cer';
    -- the 'certificate user' carries the permissions that are automatically granted 
    -- when the signed SP accesses other Databases
    CREATE USER [DB_CertUser] FROM CERTIFICATE [DB_Cert]
    GRANT CREATE TABLE TO [DB_CertUser] -- or whatever other permissions are needed
    GO

    USE TempDB1
    EXECUTE dbo.TempDB1_SP
    GO
    -- output: 'Successfully created table.'
    -- clean up: everything except the cert file, have to delete that yourself sorry
    USE [master]
    GO
    DROP DATABASE TempDB1
    DROP DATABASE OtherDB2
    GO
于 2016-11-11T01:57:32.123 回答