正在运行SQL Server 2014 Express
。登录为sa
我尝试执行以下代码。它给了我以下错误:
Msg 15247,Level 16,State 1,Line 25用户无权访问 执行此操作。
为什么?!如果我在程序中选择了SYSTEM_USER
,那么确实是sa
(合法所有者)。
USE [MyDatabase]
GO
CREATE PROCEDURE [dbo].[create_login]
@Login [nvarchar](256),
@Password [nvarchar](128)
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON
DECLARE @Sql NVARCHAR(4000)
SET @sql = N'CREATE LOGIN ' + QUOTENAME(@Login) + N' WITH PASSWORD = '
+ QUOTENAME(@Password, N'''') + N',CHECK_EXPIRATION=OFF, CHECK_POLICY=ON;'
EXEC (@sql)
END
GO
GRANT EXECUTE ON [dbo].[create_login] TO [my_simple_role]
GO
-- Let's go!
EXEC [dbo].[create_login] N'NewUser', N'c0Mpl3xP@55w0rd'
GO
-- Error! :(
如果我在外部运行语句,那么它就可以运行。
我尝试制作一个允许普通用户添加服务器登录的存储过程。以上似乎不起作用。请指教!
答案 0 :(得分:1)
登录是服务器级别对象,因此需要服务器级别权限。 EXECUTE AS <database-user>
是数据库范围的安全上下文。
通过存储过程授予普通用户特权操作的一种方法是使用映射到具有必要权限的登录名的证书对模块进行签名。这种情况下的必要步骤是:
以下是从Erland Sommarskog's web site收集的示例。请注意,每次更改时,您都需要使用证书重新签署proc。
--create database master key, if necessary
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##')
BEGIN
CREATE MASTER KEY ENCRYPTION BY PASSWORD='M@sterkEEPassw0rd';
END;
GO
CREATE CERTIFICATE SecurityAdministratorCertificate
WITH
SUBJECT = 'Allows non-privileged users to create and alter logins'
, START_DATE = '20020101'
, EXPIRY_DATE = '20300101';
GO
CREATE LOGIN SecurityAdministratorCertificateLogin
FROM CERTIFICATE SecurityAdministratorCertificate;
GO
GRANT ALTER ANY LOGIN TO SecurityAdministratorCertificateLogin;
GO
--export cert from master
DECLARE @CERTENC VARBINARY(MAX);
DECLARE @CERTPVK VARBINARY(MAX);
SELECT @CERTENC = CERTENCODED(CERT_ID(N'SecurityAdministratorCertificate'));
SELECT @CERTPVK = CERTPRIVATEKEY(CERT_ID(N'SecurityAdministratorCertificate'),
'All you need is love');
DECLARE @sql nvarchar(MAX);
SELECT @sql = N'CREATE CERTIFICATE SecurityAdministratorCertificate FROM BINARY = '
+ CONVERT(nvarchar(MAX), @CERTENC, 1)
+ ' WITH PRIVATE KEY ( BINARY = '
+ CONVERT(nvarchar(MAX), @CERTPVK, 1)
+ ', DECRYPTION BY PASSWORD = ''All you need is love'');'
--import cert into app databases
USE MyDatabase;
--create database master key, if necessary
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##')
BEGIN
CREATE MASTER KEY ENCRYPTION BY PASSWORD='M@sterkEEPassw0rd';
END;
EXEC(@sql);
GO
CREATE PROCEDURE [dbo].[create_login]
@Login [nvarchar](256),
@Password [nvarchar](128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Sql NVARCHAR(4000);
SET @sql = N'CREATE LOGIN ' + QUOTENAME(@Login) + N' WITH PASSWORD = '
+ QUOTENAME(@Password, N'''') + N',CHECK_EXPIRATION=OFF, CHECK_POLICY=ON;';
EXEC (@sql);
END
GO
--grant exec permissions to users
GRANT EXECUTE ON [dbo].[create_login] TO [my_simple_role];
GO
--sign proc with certificate
ADD SIGNATURE TO dbo.create_login BY CERTIFICATE SecurityAdministratorCertificate;
GO
修改强>
上面的示例使用数据库主密钥而不是证书专用密码来加密证书私钥。在将数据库还原或附加到其他SQL实例(不还要还原主数据库)的情况下,您需要重新创建服务器级别 master数据库中的对象,包括应用程序所需的所有登录以及master中存储的证书。要恢复证书,一种方法是在还原/附加后将证书从用户数据库复制到主服务器,然后使用权限重新创建证书登录。在这种情况下,无法自动打开DMK,因为加密数据库主密钥的服务主密钥在新实例上是不同的。需要原始密码才能在将证书复制到master数据库的脚本中手动打开DMK。用于在数据库之间复制证书的证书密码是临时的,无需保留。
以下是在还原或附加后在master中重新创建cert和cert登录的示例:
USE MyDatabase;
--open DMK with original password
OPEN MASTER KEY DECRYPTION BY PASSWORD='M@sterkEEPassw0rd';
--export cert from user database
USE MyDatabase;
DECLARE @CERTENC VARBINARY(MAX);
DECLARE @CERTPVK VARBINARY(MAX);
SELECT @CERTENC = CERTENCODED(CERT_ID(N'SecurityAdministratorCertificate'));
SELECT @CERTPVK = CERTPRIVATEKEY(CERT_ID(N'SecurityAdministratorCertificate'),
'temporary password here');
DECLARE @sql nvarchar(MAX);
SELECT @sql = N'CREATE CERTIFICATE SecurityAdministratorCertificate FROM BINARY = '
+ CONVERT(nvarchar(MAX), @CERTENC, 1)
+ ' WITH PRIVATE KEY ( BINARY = '
+ CONVERT(nvarchar(MAX), @CERTPVK, 1)
+ ', DECRYPTION BY PASSWORD = ''temporary password here'');'
SELECT @sql
CLOSE MASTER KEY;
--import cert into master
USE master;
--create database master key in new instance master database, if necessary
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##')
BEGIN
CREATE MASTER KEY ENCRYPTION BY PASSWORD='M@sterkEEPassw0rd';
END;
EXEC(@sql);
GO
--recreate login and assign permissions
CREATE LOGIN SecurityAdministratorCertificateLogin
FROM CERTIFICATE SecurityAdministratorCertificate;
GRANT ALTER ANY LOGIN TO SecurityAdministratorCertificateLogin;
GO