例如,假设您有一个像下面这样的存储过程,它在 DB 名称之前和之后强制使用两个下划线的命名约定(此示例还假设对象在[master]数据库中,我通常会尽量避免,但它确实简化了事情有点):
GO
CREATE
OR ALTER
PROCEDURE dbo.[ExampleProc]
(
@DatabaseName sysname
)
AS
SET NOCOUNT ON;
DECLARE @AlteredName sysname = QUOTENAME(N'__' + @DatabaseName + N'__');
DECLARE @SQL NVARCHAR(MAX) = N'CREATE DATABASE ' + @AlteredName + N'
ALTER AUTHORIZATION ON DATABASE::' + @AlteredName + N' TO [sa];';
EXEC(@SQL);
GO
(注意:数据库归创建它的登录名所有,因此我们更改了所有权,以便相同的登录名不能删除数据库)
您需要做的就是以下几点:
允许域用户执行这个存储过程(此时域用户会因为没有创建数据库的权限而报错):
GRANT EXECUTE ON dbo.[ExampleProc] TO [Domain\AccountWhoCreatesTheDBs];
创建证书(这将用于将代码/存储过程与权限链接):
CREATE CERTIFICATE [Permission$CreateDatabase]
ENCRYPTION BY PASSWORD = 'UseBetterPassword!'
WITH SUBJECT = 'CREATE DATABASE permission',
EXPIRY_DATE = '2099-12-31';
签署模块/存储过程(这会将存储过程链接到尚不存在的权限):
ADD SIGNATURE
TO [dbo].[ExampleProc]
BY CERTIFICATE [Permission$CreateDatabase]
WITH PASSWORD = 'UseBetterPassword!';
是的,您首先需要该域用户的登录名。如果他们只需要管理数据库(创建、更改、删除、恢复它们)的能力,那么服务器角色dbcreator就足够了。
如果您预计多个域用户需要对此进行访问,那么您应该改为为相关的 Active Directory 组创建一个登录,这样您就不必不断地管理设置多个登录。然后,您将能够将该 AD 组映射到服务器角色dbcreator。(如果您希望域中的每个人都有权创建数据库,您甚至可以使用内置的“域用户”组。)
至于如何在 C# 中实现这一点,有多种方法,这对于StackOverflow来说可能是一个更好的问题,因为它取决于您访问和查询服务器实例的方式。例如,使用ADO.NET ,您可以简单地编写一个 SQL 查询来检查当前用户的登录是否存在,如果不存在,则创建它并分配角色。或者,您甚至可以创建一个接收应用程序当前用户的过程,并为您处理该逻辑(这将更容易使用,具体取决于您使用的数据库访问框架)。但是,您可能会通过创建适当的 AD 组并将其映射到具有dbowner角色的登录名来最轻松地管理此问题。
“远程”到底是什么意思?意思是在网络上,只是没有托管在他们的计算机上?
通常,您不需要为任何人或应用程序用户分配任何提升的权限。您只需要创建一个存储过程来执行此操作所需的非常具体的步骤,授予存储过程所需的权限,然后授予这个
EXECUTE
“创建数据库”存储过程的域用户。这样,域用户将没有任何实际提升的权限。如果存储过程只是创建一个数据库,那么这就是域用户能够做的所有事情,并且只能通过执行该存储过程。例如,假设您有一个像下面这样的存储过程,它在 DB 名称之前和之后强制使用两个下划线的命名约定(此示例还假设对象在
[master]
数据库中,我通常会尽量避免,但它确实简化了事情有点):(注意:数据库归创建它的登录名所有,因此我们更改了所有权,以便相同的登录名不能删除数据库)
您需要做的就是以下几点:
sa
,否则将基于证书的登录添加到dbcreator
就可以了。完成后,域用户:
请记住,在对存储过程(或任何模块)进行签名时,签名基于该模块的代码,因此如果该代码发生更改,则签名(和链接的权限)将丢失。这需要重新签署模块以获取权限,但这是一件好事,因为它确保在不提醒您(或某些 DBA)发生某些更改的情况下无法更改代码。
有关更多详细信息/示例,请参阅我关于此主题的博客文章: