EXECUTE AS (Transact-SQL)

设置会话的执行上下文。

默认情况下,会话在用户登录时开始,在用户注销时结束。会话过程中的所有操作都受限于对该用户进行的权限检查。当运行 EXECUTE AS 语句时,会话的执行上下文将切换到指定的登录名或用户名。切换上下文之后,将根据登录名和用户安全令牌检查该帐户(而非调用 EXECUTE AS 语句的用户)的权限。实际上,在会话或模块的执行期间模拟了用户或登录帐户,或显式恢复了上下文切换。有关执行上下文的详细信息,请参阅了解执行上下文。有关上下文切换的详细信息,请参阅了解上下文切换

主题链接图标Transact-SQL 语法约定

语法

{ EXEC | EXECUTE } AS <context_specification>
[;]

<context_specification>::=
{ LOGIN | USER } = 'name'
    [ WITH { NO REVERT | COOKIE INTO @varbinary_variable } ] 
| CALLER

参数

  • LOGIN
    指定要模拟的执行上下文是一个登录。模拟范围处于服务器级别。

  • USER
    指定要模拟的上下文是当前数据库中的用户。模拟范围只限于当前数据库。对数据库用户的上下文切换不会继承该用户的服务器级别权限。

    重要说明重要提示

    当到数据库用户的上下文切换处于活动状态时,任何对数据库以外资源的访问尝试都将导致语句失败。这包括 USE database 语句、分布式查询以及引用其他数据库(使用由三或四个部分构成的标识符)的查询。若要将上下文切换的范围扩展到当前数据库之外,请参阅使用 EXECUTE AS 扩展数据库模拟

  • 'name'
    有效的用户或登录名。name 必须是 sysadmin 固定服务器角色成员,或者分别作为 sys.database_principalssys.server_principals 中的主体存在。

    name 可以指定为局部变量。

    name 必须是单独帐户,而不能是组、角色、证书、密钥或内置帐户(如 NT AUTHORITY\LocalService、NT AUTHORITY\NetworkService 或 NT AUTHORITY\LocalSystem)。

    有关详细信息,请参阅本主题后面的指定用户名或登录名。

  • NO REVERT
    指定上下文切换不能恢复到以前的上下文。

    有关恢复到以前上下文的详细信息,请参阅 REVERT (Transact-SQL)

  • COOKIE INTO **@**varbinary_variable
    指定仅当调用 REVERT WITH COOKIE 语句包含正确的 **@**varbinary_variable 值时,执行上下文才能恢复回以前的上下文。数据库引擎将 cookie 传递给 **@**varbinary_variable。

    **@**varbinary_variable 为 varbinary(100)。

  • CALLER
    当在模块内部使用时,指定模块内部的语句在模块调用方的上下文中执行。

    当在模块外部使用时,语句没有任何操作。

注释

执行上下文中的更改在下列操作之一发生之前一直有效:

  • 运行另一个 EXECUTE AS 语句。

  • 运行 REVERT 语句。

  • 删除会话。

可以通过对多个主体多次调用 EXECUTE AS 语句来创建执行上下文堆栈。在调用时,REVERT 语句将把上下文切换为上下文堆栈中上一级的登录帐户或用户。有关此行为的示例,请参阅示例 A。

指定用户名或登录名

EXECUTE AS <context_specification> 中指定的用户或登录名必须分别作为 sys.database_principalssys.server_principals 中的主体存在,否则 EXECUTE AS 语句将失败。此外,还必须为该主体授予 IMPERSONATE 权限。除非调用方是数据库所有者或 sysadmin 固定服务器角色成员,否则即使用户通过 Windows 组成员身份访问数据库或 SQL Server 实例,主体也必须存在。例如,假设条件如下:

  • CompanyDomain\SQLUsers 组具有对 Sales 数据库的访问权限。

  • CompanyDomain\SqlUser1SQLUsers 的成员,因此具有对 Sales 数据库的隐式访问权限。

虽然 CompanyDomain\SqlUser1 可以通过 SQLUsers 组中的成员身份访问数据库,但语句 EXECUTE AS USER = 'CompanyDomain\SqlUser1' 也会失败,因为 CompanyDomain\SqlUser1 并没有作为数据库中的主体存在。

如果用户处于孤立状态(关联登录名不再存在),并且该用户不是使用 WITHOUT LOGIN 创建的,EXECUTE AS 将针对此用户失败。

最佳实践

指定具有执行会话中操作所需的最低特权的登录名或用户。例如,如果只需要数据库级别的权限,则不要指定具有服务器级别权限的登录名;或者除非需要这些权限,否则不要指定数据库所有者帐户。

使用 WITH NO REVERT

当 EXECUTE AS 语句包含可选的 WITH NO REVERT 子句时,不能通过 REVERT 语句或执行另一个 EXECUTE AS 语句来重置会话的执行上下文。由该语句设置的上下文在删除会话之前一直保持有效。

当指定 WITH NO REVERT COOKIE = @varbinary\_variable 子句时,SQL Server 数据库引擎将 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 AdventureWorks;
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

下面的示例将会话的执行上下文设置为指定的用户,并指定 WITH NO REVERT COOKIE = @varbinary\_variable 子句。REVERT 语句必须指定传递给 EXECUTE AS 语句中的 @cookie 变量的值,否则,无法成功将上下文恢复为该调用方。若要执行此示例,必须存在示例 A 中所创建的 login1 登录名和 user1 用户。

DECLARE @cookie varbinary(100);
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(100);
-- 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