SQL Server 2008插入触发器未触发

发布于 2024-10-30 17:14:32 字数 430 浏览 1 评论 0原文

我在一个表上有一个 INSERT 触发器,它只是执行一个作业。

示例:

CREATE TABLE test
(
    RunDate smalldatetime
)

CREATE TRIGGER StartJob ON test 
AFTER INSERT 
AS
    EXEC msdb.dbo.sp_start_job 'TestJob'

当我向该表插入一条记录时,该作业将被解雇,没有任何问题。然而,有一些人的权限比我低(仅限数据库上的 db_datareader/db_datawriter);他们能够向表中插入一条记录,但触发器不会触发。

我是一名 SQL Server 新手,我的印象是用户不需要提升权限来触发触发器(我认为这是最大的好处之一!)。这是触发器级别的权限问题,还是工作级别的权限问题?我可以做什么来绕过这个限制?

I have an INSERT trigger on a table that simply executes a job.

Example:

CREATE TABLE test
(
    RunDate smalldatetime
)

CREATE TRIGGER StartJob ON test 
AFTER INSERT 
AS
    EXEC msdb.dbo.sp_start_job 'TestJob'

When I insert a record to this table, the job is fired of without any issue. There are a few people, however, that have lower permissions than I do (db_datareader/db_datawriter on the database only); they are able to insert a record to the table, but the trigger does not fire.

I am a SQL Server novice and I was under the impression that users did not need elevated permissions to fire off a trigger (I thought that was one of the big benefits!). Is this a permission issue at the trigger level, or at the job level? What can I do to get around this limitation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

三月梨花 2024-11-06 17:14:32

触发器将在调用者的上下文中执行,调用者可能有也可能没有访问 msdb 的权限。这似乎是你的问题。有几种方法可以使用“执行为”来扩展这些权限;它们在此链接中有详细说明

在触发器中使用模拟:

CREATE TRIGGER StartJob ON test  
with execute as owner
AFTER INSERT 
AS
EXEC msdb.dbo.sp_start_job 'TestJob'

并设置数据库值得信赖(或阅读有关登录上面的链接):

alter database TestDB set trustworthy on

另一种方法(取决于代理作业执行的操作)是利用 Service Broker 队列来处理存储过程激活。您的用户上下文将简单地调用发送队列,而在异步过程中,SvcBroker 将激活在更高权限的用户上下文中执行的存储过程。我会选择此解决方案,而不是依赖于调用代理作业的触发器。

我想测试对 Service Broker 的调用,所以我编写了这个简单的测试示例。我只是发送电子邮件,而不是调用 SSIS 包,但这与您的情况非常相似。请注意,我在脚本顶部使用了 SET TRUSTWORTHY ON。请阅读此设置的含义。

要运行此示例,您需要替换下面的电子邮件个人资料信息, 等。

use Master;
go
if exists(select * from sys.databases where name = 'TestDB')
    drop database TestDB;
create database TestDB;
go
alter database TestDB set ENABLE_BROKER; 
go
alter database TestDB set TRUSTWORTHY ON;

use TestDB;
go

------------------------------------------------------------------------------------
-- create procedure that will be called by svc broker
------------------------------------------------------------------------------------
create procedure dbo.usp_SSISCaller
as
set nocount on;
declare @dlgid uniqueidentifier;
begin try

    -- * figure out how to start SSIS package from here

    -- for now, just send an email to illustrate the async callback 
        ;receive top(1) 
                @dlgid = conversation_handle
        from SSISCallerQueue;

        if @@rowcount = 0
        begin
            return;
        end

        end conversation @dlgid;

    exec msdb.dbo.sp_send_dbmail 
        @profile_name           = '<your_profile_here>',
        @importance             = 'NORMAL',
        @sensitivity            = 'NORMAL',
        @recipients             = '<your_email_address_here>', 
        @copy_recipients        = '',
        @blind_copy_recipients  = '', 
        @subject                = 'test from ssis caller',
        @body                   = 'testing',
        @body_format            = 'TEXT'; 

    return 0;

end try
begin catch
    declare @msg varchar(max);
    select @msg = error_message();
    raiserror(@msg, 16, 1);

    return -1;
end catch;
go

------------------------------------------------------------------------------------
-- setup svcbroker objects
------------------------------------------------------------------------------------
create contract [//SSISCallerContract]
    ([http://schemas.microsoft.com/SQL/ServiceBroker/DialogTimer] sent by initiator)

create queue SSISCallerQueue 
    with status = on, 
    activation (    
        procedure_name = usp_SSISCaller,
        max_queue_readers = 1,
        execute as 'dbo' );

create service [//SSISCallerService] 
    authorization dbo
    on queue SSISCallerQueue ([//SSISCallerContract]);
go

return;


-- usage 
/*

-- put a row into the queue to trigger the call to usp_SSISCaller

begin transaction;

    declare @dlgId uniqueidentifier;

    begin dialog conversation @dlgId
                from service   [//SSISCallerService]
                to service      '//SSISCallerService', 
                                'CURRENT DATABASE'
                on contract     [//SSISCallerContract]
                with encryption = off;

    begin conversation timer (@dlgId)
            TIMEOUT = 5; -- seconds

commit transaction;
*/

The trigger will execute in the context of the caller, which may or may not have the permissions to access msdb. That seems to be your problem. There are a few ways to extend these permissions using Execute As; they are greatly detailed in this link

Use impersonation within trigger:

CREATE TRIGGER StartJob ON test  
with execute as owner
AFTER INSERT 
AS
EXEC msdb.dbo.sp_start_job 'TestJob'

And set database to trustworthy (or read about signing in above link):

alter database TestDB set trustworthy on

Another way to go (depending on what operations the agent job performs) would be to leverage a Service Broker queue to handle the stored procedure activation. Your users' context would simply call to Send On the queue while, in an asynchronous process SvcBroker would activate a stored procedure which executed in context of higher elevated user. I would opt for this solution rather than relying on a trigger calling an agent job.

I wanted to test the call to Service Broker, so I wrote this simple test example. Instead of calling an SSIS package I simply send an email, but it is very similar to your situation. Notice I use SET TRUSTWORTHY ON at the top of the script. Please read about the implications of this setting.

To run this sample you will need to substitute your email profile info below, <your_email_address_here>, etc.

use Master;
go
if exists(select * from sys.databases where name = 'TestDB')
    drop database TestDB;
create database TestDB;
go
alter database TestDB set ENABLE_BROKER; 
go
alter database TestDB set TRUSTWORTHY ON;

use TestDB;
go

------------------------------------------------------------------------------------
-- create procedure that will be called by svc broker
------------------------------------------------------------------------------------
create procedure dbo.usp_SSISCaller
as
set nocount on;
declare @dlgid uniqueidentifier;
begin try

    -- * figure out how to start SSIS package from here

    -- for now, just send an email to illustrate the async callback 
        ;receive top(1) 
                @dlgid = conversation_handle
        from SSISCallerQueue;

        if @@rowcount = 0
        begin
            return;
        end

        end conversation @dlgid;

    exec msdb.dbo.sp_send_dbmail 
        @profile_name           = '<your_profile_here>',
        @importance             = 'NORMAL',
        @sensitivity            = 'NORMAL',
        @recipients             = '<your_email_address_here>', 
        @copy_recipients        = '',
        @blind_copy_recipients  = '', 
        @subject                = 'test from ssis caller',
        @body                   = 'testing',
        @body_format            = 'TEXT'; 

    return 0;

end try
begin catch
    declare @msg varchar(max);
    select @msg = error_message();
    raiserror(@msg, 16, 1);

    return -1;
end catch;
go

------------------------------------------------------------------------------------
-- setup svcbroker objects
------------------------------------------------------------------------------------
create contract [//SSISCallerContract]
    ([http://schemas.microsoft.com/SQL/ServiceBroker/DialogTimer] sent by initiator)

create queue SSISCallerQueue 
    with status = on, 
    activation (    
        procedure_name = usp_SSISCaller,
        max_queue_readers = 1,
        execute as 'dbo' );

create service [//SSISCallerService] 
    authorization dbo
    on queue SSISCallerQueue ([//SSISCallerContract]);
go

return;


-- usage 
/*

-- put a row into the queue to trigger the call to usp_SSISCaller

begin transaction;

    declare @dlgId uniqueidentifier;

    begin dialog conversation @dlgId
                from service   [//SSISCallerService]
                to service      '//SSISCallerService', 
                                'CURRENT DATABASE'
                on contract     [//SSISCallerContract]
                with encryption = off;

    begin conversation timer (@dlgId)
            TIMEOUT = 5; -- seconds

commit transaction;
*/
山人契 2024-11-06 17:14:32

这将是工作级别的权限。您可以在 MSDB 中为这些用户分配 SQLAgentReaderRole 以便能够启动作业,考虑到他们将被添加到拥有该作业的组中。如果他们不属于拥有这份工作的团体,事情就会变得更加困难。

It would be permissions at the job level. You can possibly assign those users the SQLAgentReaderRole in MSDB to be able to start a job, considering that they would be added to a group that owned the job. If they are not in a group which owns the job, it gets more difficult.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文