EXECUTE AS (Transact-SQL)
設定工作階段的執行內容。
依預設,工作階段會在使用者登入時起始,在使用者登出時結束。 工作階段期間的所有作業是依對該使用者的權限檢查而定。 執行 EXECUTE AS 陳述式時,工作階段的執行內容會切換到指定的登入或使用者名稱。 在內容切換之後,權限檢查是對該帳戶的登入和使用者安全性 Token,而不是對呼叫 EXECUTE AS 陳述式的人員。 基本上,使用者或登入帳戶的模擬是在工作階段或模組執行的期間,否則會明確還原內容切換。
語法
{ EXEC | EXECUTE } AS <context_specification>
[;]
<context_specification>::=
{ LOGIN | USER } = 'name'
[ WITH { NO REVERT | COOKIE INTO @varbinary_variable } ]
| CALLER
引數
LOGIN
指定您要模擬的執行內容是登入。 模擬範圍是在伺服器層級。[!附註]
自主資料庫無法使用這個選項。
USER
指定您要模擬的內容是目前資料庫中的使用者。 模擬範圍僅限於目前資料庫。 通往資料庫使用者的內容切換不會繼承該使用者的伺服器層級權限。重要事項 如果通往資料庫使用者的內容切換在使用中,任何人想要存取資料庫以外的資源,都會導致陳述式失敗。 其中包括 USE database 陳述式、分散式查詢,以及參考另一個使用三或四部分識別碼之資料庫的查詢。
' name '
有效的使用者或登入名稱。 name 必須是系統管理員 (sysadmin) 固定伺服器角色的成員,或是以主體形式分別存在於 sys.database_principals 或 sys.server_principals 中。name 可以指定為本機變數。
name 必須是單一帳戶,不可以是群組、角色、憑證、金鑰或內建帳戶,例如 NT AUTHORITY\LocalService、NT AUTHORITY\NetworkService 或 NT AUTHORITY\LocalSystem。
如需詳細資訊,請參閱本主題稍後的指定使用者或登入名稱。
NO REVERT
指定內容切換不能還原回先前的內容。 NO REVERT 選項只能在特定層級使用。如需有關還原到先前內容的詳細資訊,請參閱<REVERT (Transact-SQL)>。
COOKIE INTO **@**varbinary_variable
指定如果呼叫的 REVERT WITH COOKIE 陳述式包含正確的 **@**varbinary_variable 值,則執行內容只可以還原回先前的內容。 Database Engine 會將 Cookie 傳送至 **@**varbinary_variable。 COOKIE INTO 選項只能在特定層級使用。**@**varbinary_variable 是 varbinary(8000)。
[!附註]
目前 Cookie OUTPUT 參數記載成 varbinary(8000),是正確的長度上限。 但目前的實作會傳回 varbinary(100)。 應用程式應保留 varbinary(8000),如此後續版本的 Cookie 傳回大小如有增加,應用程式才可繼續正常地運作。
CALLER
用於模組內部時,指定模組內部的陳述式是在模組呼叫者的內容中執行。用於模組外部時,陳述式沒有動作。
備註
執行內容中的變更持續有效,直到發生下列項目之一為止:
執行另一個 EXECUTE AS 陳述式。
執行 REVERT 陳述式。
卸除工作階段。
造成執行的命令結束的預存程式或觸發程序。
您可以藉由跨多個主體多次呼叫 EXECUTE AS 陳述式來建立執行內容堆疊。 REVERT 陳述式被呼叫時,會將內容切換到內容堆疊中上一層級的登入或使用者。 如需這個行為的示範,請參閱範例 A。
指定使用者或登入名稱
在 EXECUTE AS <context_specification> 中指定的使用者或登入名稱,必須以主體形式分別存在於 sys.database_principals 或 sys.server_principals 中,否則 EXECUTE AS 陳述式就會失敗。 此外,還必須授與主體的 IMPERSONATE 權限。 除非呼叫者是資料庫擁有者,或是系統管理員 (sysadmin) 固定伺服器角色的成員,否則主體必須存在,即使當使用者透過 Windows 群組成員資格在存取資料庫或 SQL Server 的執行個體時也一樣。 例如,假設有下列情況:
CompanyDomain\SQLUsers 群組有權存取 Sales 資料庫。
CompanyDomain\SqlUser1 是 SQLUsers 的成員,因此對 Sales 資料庫具有隱含的存取權。
雖然 CompanyDomain\SqlUser1 有權透過 SQLUsers 群組中的成員資格來存取資料庫,但是 EXECUTE AS USER = 'CompanyDomain\SqlUser1' 陳述式會失敗,因為 CompanyDomain\SqlUser1 並未以主體形式存在於資料庫中。
如果使用者被遺棄 (相關聯的登入不存在),而且使用者並非使用 WITHOUT LOGIN 建立的,該使用者的 EXECUTE AS 將會失敗。
最佳作法
指定一個登入或使用者,它具有執行工作階段中作業所需要的最低權限。 例如,如果只需要資料庫層級權限,就不要指定具有伺服器層級權限的登入名稱;或者,除非需要其權限,否則不要指定資料庫擁有者帳戶。
注意 |
---|
只要 Database Engine 可以解析名稱,EXECUTE AS 陳述式即可順利地運作。 即使 Windows 使用者無權存取 SQL Server,只要網域使用者存在,Windows 或許可以解析 Database Engine 的使用者。 這可能會導致無權存取 SQL Server 的使用者順利地登入,但模擬登入只有 public 或 guest 的權限。 |
使用 WITH NO REVERT
當 EXECUTE AS 陳述式包括選擇性的 WITH NO REVERT 子句時,不能使用 REVERT 或藉由執行另一個 EXECUTE AS 陳述式來重設工作階段的執行內容。 陳述式設定的內容會持續有效,直到卸除工作階段為止。
指定 WITH NO REVERT COOKIE = @ varbinary_variable 子句時,SQL Server Database Engine 會將 Cookie 值傳遞到 @varbinary\_variable。 只有當呼叫的 REVERT WITH COOKIE = @varbinary\_variable 陳述式包含相同的 @varbinary\_variable 值時,該陳述式所設定的執行環境才能還原到先前的環境。
這個選項在使用連接共用的環境中相當有用。 連接共用是資料庫連接群組的維護,這些連接是供應用程式伺服器上的應用程式重複使用。 因為傳送到 @varbinary\_variable 的值只有 EXECUTE AS 陳述式的呼叫者知道,呼叫者可以保證其所建立的執行內容不會被別人變更。
決定原始登入
使用 ORIGINAL_LOGIN 函數來傳回連接到 SQL Server 執行個體的登入名稱。 您可以利用這個函數來傳回有許多明確或隱含內容切換的工作階段中原始登入的識別。
權限
若要指定某項登入的 EXECUTE AS 權限,則這位呼叫者必須具有指定之登入名稱的 IMPERSONATE 權限。 若要指定資料庫使用者的 EXECUTE AS 權限,則這位呼叫者必須具有指定之使用者名稱的 IMPERSONATE 權限。 當指定 EXECUTE AS CALLER 時,不需要 IMPERSONATE 權限。
範例
A.使用 EXECUTE AS 及 REVERT 切換內容
下列範例會利用多個主體來建立一個內容執行堆疊。 然後再用 REVERT 陳述式,將執行內容重設為前一個呼叫者。 REVERT 陳述式在上移堆疊時會執行多次,直到執行內容設為原始呼叫者為止。
USE AdventureWorks2012;
GO
--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 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 current execution context.
SELECT SUSER_NAME(), USER_NAME();
REVERT;
--Display current execution context.
SELECT SUSER_NAME(), USER_NAME();
--Remove temporary principals.
DROP LOGIN login1;
DROP LOGIN login2;
DROP USER user1;
DROP USER user2;
GO
B.使用 WITH COOKIE 子句
下列範例會將工作階段的執行內容設為指定使用者,並且指定 WITH NO REVERT COOKIE = @varbinary\_variable 子句。 REVERT 陳述式必須指定傳給 EXECUTE AS 陳述式中的 @cookie 變數值,才能順利將內容還原回呼叫者。 若要執行這個範例,則必須具備在範例 A 中建立的 login1 登入和 user1 使用者。
DECLARE @cookie varbinary(8000);
EXECUTE AS USER = 'user1' WITH COOKIE INTO @cookie;
-- Store the cookie in a safe location in your application.
-- Verify the context switch.
SELECT SUSER_NAME(), USER_NAME();
--Display the cookie value.
SELECT @cookie;
GO
-- Use the cookie in the REVERT statement.
DECLARE @cookie varbinary(8000);
-- Set the cookie value to the one from the SELECT @cookie statement.
SET @cookie = <value from the SELECT @cookie statement>;
REVERT WITH COOKIE = @cookie;
-- Verify the context switch reverted.
SELECT SUSER_NAME(), USER_NAME();
GO