Sql-Server

伺服器範圍的 DDL 觸發器權限問題

  • February 2, 2014

我正在嘗試實現一個伺服器範圍的 DDL 觸發器,它將使用與此處找到的文章非常相似的腳本來審核伺服器上數據庫中的 DDL 更改

觸發器會將 DDL 事件記錄到一個數據庫中的一個表中,但是我遇到了權限問題,一些使用者,甚至我自己擁有系統管理員權限,都會收到以下錯誤消息。

Msg 297, Level 16, State 1, Procedure LogDDLEvent, Line 19
The user does not have permission to perform this action.

我已經閱讀了有關使用該WITH EXECUTE AS子句並專門為執行觸發器創建登錄的資訊,儘管這似乎並沒有解決問題。

有人可以就實現此類觸發器的正確方法提出建議,以及使用者或特定登錄需要哪些權限才能在 WITH EXECUTE AS 中使用?

編輯:一些進一步的資訊

伺服器正在執行 SQL Server 2008 R2,並且 DDL 觸發器設置為 DDL_EVENTS,如下所示:

CREATE TRIGGER LogDDLEvent
ON ALL SERVER
FOR DDL_EVENTS
AS

DECLARE     @eventInfo XML
SET         @eventInfo = EVENTDATA()

INSERT INTO Tools.audit.DDLEvent
VALUES
(
     REPLACE(CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/PostTime)')),'T', ' ') -- EventTime
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/EventType)')) -- EventType
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/LoginName)')) -- LoginName
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/UserName)')) -- UserName
     , CAST(HOST_NAME() AS VARCHAR(128)) -- MachineName
     , (SELECT   CAST(client_net_address AS VARCHAR(128))
           FROM  sys.dm_exec_connections
           WHERE Session_id = CONVERT(INT, @eventInfo.value('data(/EVENT_INSTANCE/SPID)[1]', 'int'))) -- IPAddress
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/DatabaseName)')) -- DatabaseName
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/SchemaName)')) -- SchemaName
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/ObjectName)')) -- ObjectName
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/ObjectType)')) -- ObjectType
     , CONVERT(VARCHAR(MAX), @eventInfo.query('data(/EVENT_INSTANCE/TSQLCommand/CommandText)')) -- DDLCommand
     , @eventInfo -- DDLEventXML
)

上面的腳本是我最初創建觸發器的方式,這對我和其他一些使用者來說效果很好,儘管對特定數據庫具有 db_owner 角色的使用者一直收到上面的錯誤消息。

在嘗試實現 WITH EXECUTE AS 後,我發現觸發器對我自己不起作用。

將觸發器設置為 EXECUTE WITH ‘sa’ 似乎可以解決問題。不確定這是否會帶來任何安全問題。我嘗試創建一個僅對工具數據庫和 DDLEvent 表具有權限的單獨登錄,但非系統管理員使用者出錯。

CREATE TRIGGER LogDDLEvent
ON ALL SERVER
WITH EXECUTE AS 'sa'
FOR DDL_EVENTS
AS

DECLARE     @eventInfo XML
SET         @eventInfo = EVENTDATA()

INSERT INTO Tools.audit.DDLEvent
VALUES
(
     REPLACE(CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/PostTime)')),'T', ' ') -- EventTime
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/EventType)')) -- EventType
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/LoginName)')) -- LoginName
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/UserName)')) -- UserName
     , CAST(HOST_NAME() AS VARCHAR(128)) -- MachineName
     , (SELECT   CAST(client_net_address AS VARCHAR(128))
           FROM  sys.dm_exec_connections
           WHERE Session_id = CONVERT(INT, @eventInfo.value('data(/EVENT_INSTANCE/SPID)[1]', 'int'))) -- IPAddress
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/DatabaseName)')) -- DatabaseName
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/SchemaName)')) -- SchemaName
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/ObjectName)')) -- ObjectName
     , CONVERT(VARCHAR(128), @eventInfo.query('data(/EVENT_INSTANCE/ObjectType)')) -- ObjectType
     , CONVERT(VARCHAR(MAX), @eventInfo.query('data(/EVENT_INSTANCE/TSQLCommand/CommandText)')) -- DDLCommand
     , @eventInfo -- DDLEventXML
)

引用自:https://dba.stackexchange.com/questions/49270