如何启用非sysadmin帐户执行" DBCC CHECKIDENT"?

时间:2017-06-13 16:27:48

标签: sql-server

在每次DAO测试之前,我清理我的数据库,我需要重置某些表的标识值。我创建了以下存储过程:

CREATE PROCEDURE SET_IDENTITY
    @pTableName           varchar(120),
    @pSeedValue           int
AS
BEGIN
    DBCC CHECKIDENT(@pTableName, RESEED, @pSeedValue);
END

我的问题是我需要使用" normal"来调用此存储过程。用户。为了正常工作,此用户不能是以下成员:sysadmin,db_owner,db_ddladmin。

我试过了:

a)CREATE PROCEDURE WITH EXECUTE AS OWNER

b)EXECUTE AS USER = 'sa' before call DBCC CHECKIDENT

但在这两种情况下我都回来了:

服务器主体sa无法在当前安全上下文中访问数据库my_db_name

我使用的是Microsoft SQL Server Express(64位)11.0.2100.60

提前谢谢你,

阿贝尔

2 个答案:

答案 0 :(得分:1)

这很容易做到,但一般来说,每次都不应该需要来重置身份值。特定的身份值无关紧要,因此唯一的问题应该是由于重复测试而可能达到最大值。在这种情况下,我不建议每次重置,因为它也是一个很好的测试,让ID达到高值,这样你就可以确保所有代码路径正确处理它们并找到用户之前没有的区域;-)

话虽这么说,你需要做的就是(假设这本地化为单个数据库)是创建一个非对称密钥,然后从中创建一个用户,然后将该用户添加到db_ddladmin固定的数据库角色,最后使用相同的非对称密钥签署您的存储过程。

以下示例说明了此行为:

USE [tempdb];

CREATE TABLE dbo.CheckIdent
(
  [ID] INT NOT NULL IDENTITY(1, 1) CONSTRAINT [PK_CheckIdentity] PRIMARY KEY,
  [Something] VARCHAR(50)
);

EXEC(N'
CREATE PROCEDURE dbo.SET_IDENTITY
    @pTableName           sysname,
    @pSeedValue           int
AS
BEGIN
    DBCC CHECKIDENT(@pTableName, RESEED, @pSeedValue);
END;
');

CREATE USER [MrNobody] WITHOUT LOGIN;

GRANT EXECUTE ON dbo.SET_IDENTITY TO [MrNobody];

-------

EXECUTE AS USER = N'MrNobody';
SELECT SESSION_USER AS [CurrentUser], ORIGINAL_LOGIN() AS [OriginalLogin];

EXEC dbo.SET_IDENTITY N'dbo.CheckIdent', 12;
/*
Msg 2557, Level 14, State 5, Procedure SET_IDENTITY, Line 7 [Batch Start Line 30]
User 'MrNobody' does not have permission to run DBCC CHECKIDENT for object 'CheckIdent'.
*/

REVERT;
SELECT SESSION_USER AS [CurrentUser], ORIGINAL_LOGIN() AS [OriginalLogin];

-------

CREATE ASYMMETRIC KEY [DdlAdminPermissionsKey]
  WITH ALGORITHM = RSA_2048
  ENCRYPTION BY PASSWORD = 'not_a_good_password';

CREATE USER [DdlAdminPermissions]
  FROM ASYMMETRIC KEY [DdlAdminPermissionsKey];

ALTER ROLE [db_ddladmin] ADD MEMBER [DdlAdminPermissions];

ADD SIGNATURE
  TO dbo.SET_IDENTITY
  BY ASYMMETRIC KEY [DdlAdminPermissionsKey]
  WITH PASSWORD = 'not_a_good_password';

-------

EXECUTE AS USER = N'MrNobody';
SELECT SESSION_USER AS [CurrentUser], ORIGINAL_LOGIN() AS [OriginalLogin];

EXEC dbo.SET_IDENTITY N'dbo.CheckIdent', 12;
-- Success!

REVERT;
SELECT SESSION_USER AS [CurrentUser], ORIGINAL_LOGIN() AS [OriginalLogin];

其他小调:

  1. 您无法以User = sa执行,因为sa是Login(服务器级别)而不是User(数据库级别)。您可以使用EXECUTE AS LOGIN = 'sa';,但这需要IMPERSONATE权限,这是一个安全漏洞,因为非特权登录可以随时运行EXECUTE AS LOGIN = 'sa'。所以不要这样做。
  2. 对于包含SQL Server对象,索引等名称的变量/参数,您应该使用NVARCHAR而不是VARCHAR。大多数内部名称使用sysnameNVARCHAR(128)sysname的系统别名,因此{{1}}通常是首选的数据类型。

答案 1 :(得分:0)

来电者必须拥有架构或 db_owner

来自doc:DBCC CHECKIDENT

  

权限

     

来电者必须拥有包含表的架构,或者是 sysadmin 固定服务器角色的成员, db_owner 固定数据库角色,或 db_ddladmin 固定数据库角色。

LiveDemo