"服务经纪人"服务器负责人" sa"无法在当前安全上下文下访问数据库

时间:2014-04-11 09:13:30

标签: sql-server tsql stored-procedures service-broker sql-server-2012-express

我正在使用SQL Server 2012 Express。

我正在使用Service Broker以异步方式运行存储过程。

激活过程必须访问另一个数据库才能执行另一个存储过程。这是代码:

CREATE PROCEDURE [dbo].[GetNewCodes]
    @gintNewCodes bigint,   
    @presNewCodes tinyint,
    @levelNewCodes bigint,
    @quantityNewCodes smallint
AS

    -- Get new codes from INCIC database.
    DECLARE @return_value int,
            @xmlGenerated xml,
            @xmlString NVARCHAR(MAX)

    SET NOCOUNT ON;

        -- Set that this stored procedure is running
        update dbo.RunningSPs with (serializable) set conf_value = 1
        where sp_name = N'GetNewCodes'

        if @@rowcount = 0
        begin
            insert dbo.RunningSPs(sp_name, conf_value) values (N'GetNewCodes', 1)
        end

    EXEC    @return_value = [INCIC].[dbo].[ReadCodeBuffer]
            @gint = @gintNewCodes,
            @pres = @presNewCodes,
            @level = @levelNewCodes,
            @quantity = @quantityNewCodes,
            @xmlGenerated = @xmlGenerated OUTPUT

    SET @xmlString = cast(@xmlGenerated as nvarchar(max))

    -- Process these new codes on TRZ.
    EXEC dbo.ProcessCodes @XmlString = @xmlString

    -- Update that we are not running this procedure any more.
    update dbo.RunningSPs with (serializable) set conf_value = 0
    where sp_name = N'GetNewCodes'

    if @@rowcount = 0
    begin
        insert dbo.RunningSPs(sp_name, conf_value) values (N'GetNewCodes', 0)
    end

问题在于:[INCIC].[dbo].[ReadCodeBuffer],错误消息为:

  

错误:50000
  过程中不可恢复的错误GetNewCodes:916:服务器主体" sa"无法访问数据库" INCIC"在当前的安全背景下。

我已按照此tutorial实施服务,队列和激活存储过程。

如何解决此问题?

2 个答案:

答案 0 :(得分:5)

阅读Call a procedure in another database from an activated procedure

问题是激活的过程是在EXECUTE AS USER上下文中运行的,因此受数据库模拟限制(它们在数据库中沙箱化)。所有内容都在Extending Database Impersonation by Using EXECUTE AS中解释。

解决方案是签署激活的过程并创建从目标数据库中的签名证书派生的用户,并为此派生用户授予所需的权限。第一个链接显示了一个完整的示例。

答案 1 :(得分:0)

Remus Rusanu的回答显然是确定无误的。 (任何与Broker Services打交道的人都知道他的专业知识和宝贵的博客。)

我只是想记录一下我的经验,因为谷歌在搜索“服务器主体”时会指向这个问题sa“无法访问数据库......

就我而言,我在激活的过程中调用了另一个数据库,但是直接调用了sql语句,而不是存储过程。

最初,跨数据库调用在没有签名证书和使用模拟的情况下工作正常。然后,在一个小的语法更改后,它开始返回上面的错误消息。

以下是无需签名证书的情况:

IF  EXISTS (SELECT name FROM sys.databases WHERE name = N'MyOtherDb')

这就是引发安全例外的原因:

IF DB_ID(N'MyOtherDb') IS NOT NULL