防止用户在用户数据库 SQL 服务器中使用 "dbo"

Prevent User Usage of "dbo" in User Databases SQL Server

我试图阻止在我的 SQL 服务器数据库中使用默认架构“dbo”。这被应用于一个现有的长期项目,并进行持续维护,开发人员还管理 SQL 服务器(都是系统管理员)。

这样做的主要原因是为了更好地跟踪代码和 SQL 服务器对象之间的依赖关系,以便我们可以慢慢迁移到更好的命名约定。例如。 “dbo.Users”、“dbo.Projects”、“dbo.Categories”在数据库中一旦创建就几乎不可能在代码中找到,因为“dbo”。通常被排除在 SQL 语法之外。

但是,正确定义的模式需要在代码中使用。例如。 “Tracker.Users”、“Tracker.Projects”等...

即使我们将标准设置为不对对象使用“dbo”,但由于 management/business 开发速度的压力,它仍然会意外发生。

注意:我提出这个问题只是为了提供一个其他人可以找到有用的解决方案

编辑:正如所指出的,对于非系统管理员用户,所述安全选项是一个可行的解决方案,但是 DDL 触发器解决方案也适用于系统管理员用户。许多必须在那里管理自己的盒子的小团队就是这种情况。

以下数据库 DLL 触发器在 SQL 管理器 GUI 和通过手动 TSQL 代码尝试为指定类型创建对象时导致错误反馈。

它包括一种拥有特殊用户的方法,并向尝试创建对象的用户提供明确的反馈。它还可以向系统管理员用户提出错误。

它不会影响现有对象,除非 GUI/SQL 尝试删除并创建现有的基于“dbo”的对象。

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [CREATE_Prevent_dbo_Usage_2] ON DATABASE 
    FOR CREATE_TABLE, CREATE_VIEW, CREATE_PROCEDURE, CREATE_FUNCTION
AS 

DECLARE @E XML = EVENTDATA();

DECLARE @CurrentDB nvarchar(200)=@E.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'NVARCHAR(2000)');
DECLARE @TriggerFeedbackName nvarchar(max)=@CurrentDB+N'.CREATE_Prevent_dbo_Usage'; -- used to feedback the trigger name on a failure so the user can disable it (or know where the issue is raised from)

DECLARE @temp nvarchar(2000)='';
DECLARE @SchemaName nvarchar(2000)=@E.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(2000)');
DECLARE @ObjectName nvarchar(2000)=@E.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(2000)');
DECLARE @LoginName nvarchar(2000)=@E.value('(/EVENT_INSTANCE/LoginName)[1]', 'NVARCHAR(2000)');

DECLARE @CurrentObject nvarchar(200)=''; -- Schema.Table

IF @LoginName NOT IN ('specialUser') BEGIN -- users to exclude in evaluation.
    IF CASE WHEN @SchemaName IN ('dbo') THEN 1 ELSE 0 END = 1 BEGIN -- is a DBO attempt to create.
        SET @CurrentObject = @SchemaName+'.'+@ObjectName; -- grouped here for easy cut and paste/modify.
        SET @temp='Cannot create "'+@CurrentObject+'".
This Database "'+@CurrentDB+'" has had creation of "dbo" objects restricted to improve code maintainability.
Use an existing schema or create a new one to group the purpose of the objects/code.
Disable this Trigger TEMPORARILY if you need to do some advanced manipulation of it.
(This message was produced by "'+@TriggerFeedbackName+'")';
        throw 51000,@temp,1;
    END
END

GO

ENABLE TRIGGER [CREATE_Prevent_dbo_Usage] ON DATABASE
GO

我觉得 dbo 架构上的 DENY ALTER 会简单 10,000 倍:

DENY ALTER ON SCHEMA::dbo TO [<role(s)/user(s)/group(s)>];

如果每个人都以 sa 的身份连接,那就不太方便了,但是,好吧,先解决