我正在尝试实现一个服务器范围的 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 表具有权限的单独登录,但非系统管理员用户出错。