SQL Server ->> EXECUTE AS LOGIN/USER和Revert表達式


EXECUTE AS LOGIN/USER和Revert表達式都是從SQL Server 2005就有。Revert的作用是用於切換當前過程的執行上下文返回上一個EXECUTE AS 語句發生之前的安全上下文。Revert可以在存儲過程、ad-hoc環境下、用戶定義函數中使用。Revert是和 EXECUTE AS LOGIN/USER配合起來使用的。

 

這里需要先講一個執行上下文(Execution Context)的概念。當一個用戶開啟一個會話到SQL Server之后,整個會話的權限檢查都是基於登陸用戶的身份。

EXECUTE AS LOGIN/USER可以借以某個登陸用戶和數據庫用戶的身份去執行某些操作,直到下一個REVERT語句發生才切換回caller的身份。當為LOGIN的時候,復制的用戶身份是server層面的,所以是對於整個server層面的所有數據庫而言。而當為user的時候,並不會去復制login層面的權限。但是這里MSDN說的不對,這里有一段msdn在EXECUTE AS (Transact-SQL)中的話:

While the context switch to the database user is active, any attempt to access resources outside of the database will cause the statement to fail. This includes USE database statements, distributed queries, and queries that reference another database that uses three- or four-part identifiers.

 

它的意思是一旦只要執行上下文切換成功且沒有用REVERT切換回caller的上下文,任何對當前數據庫范圍外的其他數據庫資源的訪問都會失敗,包括了USE <database>語句,分布式查詢和帶有3個以上標識符的對象引用。這里說的不對而且解釋的也不清楚。不是說所有的都失敗。失敗的原因是當我們以某個數據庫用戶的身份切換后,對於其他數據庫的資源訪問都將以guest用戶身份進行,包括USE <database>語句。而我們都知道除了tempdb,msdb和master三個db,用戶數據庫和model數據庫的guest用戶是被禁用的。所以當我們試圖去切換到其他數據庫的安全上下文的時候就根本找不到一個用戶身份。但是,我們是可以成功執行USE <database>語句去切換到tempdb,msdb和master三個db。

 

這里引用一個MSDN的例子

-- Create two temporary principals.
CREATE LOGIN login1 WITH PASSWORD = 'J345#$)thb';
CREATE LOGIN login2 WITH PASSWORD = 'Uor80$23b';
GO
CREATE USER user1 FOR LOGIN login1;
CREATE USER user2 FOR LOGIN login2;
GO
-- Give IMPERSONATE permissions on user2 to user1
-- so that user1 can successfully set the execution context to user2.
GRANT IMPERSONATE ON USER:: user2 TO user1;
GO


-- Display current execution context.
SELECT SUSER_NAME(), USER_NAME();
-- Set the execution context to login1. 
EXECUTE AS LOGIN = 'login1';
-- Verify that the execution context is now login1.
SELECT SUSER_NAME(), USER_NAME();
-- Login1 sets the execution context to login2.
EXECUTE AS USER = 'user2';
-- Display current execution context.
SELECT SUSER_NAME(), USER_NAME();
-- The execution context stack now has three principals: the originating caller, login1, and login2.
-- The following REVERT statements will reset the execution context to the previous context.
REVERT;
-- Display the current execution context.
SELECT SUSER_NAME(), USER_NAME();
REVERT;
-- Display the current execution context.
SELECT SUSER_NAME(), USER_NAME();

-- Remove the temporary principals.
DROP LOGIN login1;
DROP LOGIN login2;
DROP USER user1;
DROP USER user2;
GO    

 

REVERT還支持一個WITH COOKIE = @varbinary_variable選項。這個東西的作用主要是為了保證在啟動連接池(connection pool)的情況下,當前會話的上下文不被下一個重用會話的人切換。這個東西就像一個密碼一樣的東西,你保存了密碼,就只有你自己知道密碼,才能去解碼。

 

--Create temporary principal 
CREATE LOGIN login1 WITH PASSWORD = 'P@$$w0rdO1'; 
GO 
CREATE USER user1 FOR LOGIN login1; 
GO

DECLARE @cookie varbinary(100); --variable to store the cookie 
--switch execution context, generate cookie and assign it to variable 
EXECUTE AS USER = 'user1' WITH COOKIE INTO @cookie;

select @cookie

select CURRENT_USER

EXECUTE AS USER = 'user2';

-- Use the cookie in the REVERT statement. 
SELECT CURRENT_USER AS UserName;  

DECLARE @cookie varbinary(100); 
-- Set the cookie value to the one from the SELECT @cookie statement. 
SET @cookie = 0x21873959E804DD435976EA5D25B7352431A98B4F144C76F6B1502C5AA3C20F30105842EEA9C361B3DA03B2DBD36E0E070100;
REVERT WITH COOKIE = @cookie; 
-- Verify the context switch reverted. 
SELECT CURRENT_USER AS UserName;  
GO

 

上面對動態語句同樣適用

EXECUTE AS USER = 'user1';

select CURRENT_USER

EXECUTE AS USER = 'user2';

SELECT CURRENT_USER AS UserName;  

EXEC('SELECT CURRENT_USER AS UserName;') 

SELECT CURRENT_USER AS UserName;  

REVERT

 

 對於EXECUTE AS USER其實就沒有太多好講的是了,倒是對於EXECUTE AS LOGIN還有一點我好奇的,就是多個數據庫我可以存在對多個數據庫的安全上下文(因為我可以在不同的數據庫下再執行不同的EXECUTE AS LOGIN/USER語句去切換到其他用戶的安全上下文),那是不是可以隨便切換呢?答案當然是否定的。這里上下文也有和事務一樣的特性,就是你可以在某個庫下任意嵌套多層的上下文切換。當你用USE <database>語句切換到tempdb,msdb,master庫並切換上下文的時候是可以的,只是如果你在tempdb中的上下文切換還沒有結束(REVERT)就切換回原來的數據庫就不行了,這就如同事務一樣,你在事務1開啟了事務2,事務2你不rollback或者commit怎么跳回到上一層的事務。但是你可以繼續切換到msdb下(另一個或者說第三個數據庫下)這是沒問題的。

 

總結一下:

安全上下文切換確實是個好玩的東西,也是有一定的學問在里面的。

1)EXECUTE AS LOGIN/USER各自復制的安全上下文特性不一樣;

2)在一個數據庫下,可以多次得嵌套上下文切換,當然我相信不會有人去這么干,這樣的復雜代碼設計應該不會有人去這么干吧。

3)對於EXECUTE AS USER,實際是可以再使用USE <database>的,只是變成了guest身份;

4)在不結束某個庫的上下文切換前是無法跳轉回原來的數據庫,這點和事務的原理類似,不管當前的login是否在先前的數據庫中涉及了上下文切換;

 

參考:

EXECUTE AS (Transact-SQL)

REVERT (Transact-SQL)

Switching Stored Procedure Execution Context in SQL Server using the REVERT clause

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM