2017-06-13 58 views
1

在每次DAO測試之前,我清理我的數據庫,並且需要重置某些表的標識值。我創建了以下存儲過程:如何啓用非系統管理員帳戶來執行「DBCC CHECKIDENT」?

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

我的問題是我需要用「普通」用戶調用此存儲過程。按順序工作,該用戶不能成爲:sysadmin,db_owner,db_ddladmin的成員。

我已經試過:

一)CREATE PROCEDURE WITH EXECUTE AS OWNER

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

但在這兩種情況下,我回來了:

服務器主體sa無法訪問在當前安全上下文下的數據庫my_db_name

我使用微軟的SQL Server Express(64位)11.0.2100.60

謝謝你在前進,

阿貝爾

+0

如果您的環境允許,請嘗試使用'ALTER AUTHORIZATION ON DATABASE :: [mydb] TO [sa]'將數據庫所有者設置爲SQL Server可以驗證的內容(確保您的數據庫沒有組帳戶首先由設計師設計一個所有者!)然後'EXECUTE AS OWNER'應該可以工作。對於更強大的解決方案,您可以使用加密簽名爲存儲過程提供必要的許可,但[涉及更多](http://sommarskog.se/grantperm.html#Certificates)。 –

+0

另一種可能的解決方案是,如果「clean」意味着「清除整個表」,則使用'TRUNCATE TABLE',作爲副作用也會重置身份並且只需要表中的'ALTER'權限。還要考慮使用[數據庫項目](https://msdn.microsoft.com/library/hh272677)來創建一個乾淨的空數據庫,您可以在每次測試運行之前部署(或者每次測試,甚至是,但這可能太慢)。另一種選擇是恢復到[快照](https://docs.microsoft.com/zh-cn/sql/relational-databases/databases/database-snapshots-sql-server)或分離/附加空的數據庫。 –

+0

規範聲明您不能在表上使用TRUNCATE TABLE,而是由FOREIGN KEY約束引用。 –

回答

0

來電有自己的模式或者是的db_owner

從DOC:DBCC CHECKIDENT

個權限

來電必須擁有包含表的模式,或者是系統管理員固定服務器角色的成員,該的db_owner固定數據庫角色,或者db_ddladmin固定數據庫角色。

LiveDemo

+0

@AbelaneIROS您是否嘗試過CREATE PROCEDURE WITH EXECUTE AS'user_name'' 'user_name'擁有模式還是db_owner? – lad2025

0

這是很容易做到,但總的來講,你不應該需要每次重置標識值。具體的身份值應該不重要,所以唯一的擔心應該是可能由於重複測試而達到最大值。在這種情況下,我不建議每次都重新設置,因爲讓ID達到較高值也是一個很好的測試,因此您可以確保所有代碼路徑正確處理它們,並找到不在用戶使用之前的區域;-) 。這就是說,你需要做的就是創建一個非對稱密鑰,然後從中創建一個用戶,然後將該用戶添加到​​固定的數據庫角色,並最終簽名使用相同非對稱密鑰的存儲過程。

下面的例子說明了這種行爲:

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. 您不能執行作爲用戶= sa因爲sa是登錄(服務器級別),而不是用戶(數據庫水平)。您可以使用EXECUTE AS LOGIN = 'sa';,但那需要IMPERSONATE權限,並且是一個安全漏洞,因爲非特權登錄可以隨時運行EXECUTE AS LOGIN = 'sa'。所以不要這樣做。
  2. 對於包含SQL Server對象名稱,索引等的變量/參數,應該使用NVARCHAR而不是VARCHAR。大多數內部名稱使用sysname,這是NVARCHAR(128)的系統別名,所以sysname通常是首選數據類型。