跨存储过程调用时REVERT为何无法恢复至original_login()?
问题:REVERT语句在跨存储过程调用时的生效范围
我有两个存储过程,Sales.spExec1会调用dbo.spExec2。在dbo.spExec2里执行REVERT语句时,没法恢复到original_login()对应的初始登录身份;但在执行了EXECUTE AS USER的Sales.spExec1里执行REVERT却能正常生效。这是不是意味着REVERT仅在发起身份切换的存储过程内有效?
对应的存储过程代码如下:
CREATE PROCEDURE Sales.spExec1 AS BEGIN PRINT SUSER_SNAME() -- 'MyDomain\Bob.Smith' PRINT original_login() -- 'MyDomain\Bob.Smith' EXECUTE AS USER = 'TempUser'; EXEC dbo.spExec2 REVERT; /* REVERT works in SP where initial EXECUTE AS USER ran */ print SUSER_SNAME() -- 'MyDomain\Bob.Smith' print original_login() -- 'MyDomain\Bob.Smith' END; GO CREATE PROCEDURE dbo.spExec2 AS BEGIN PRINT SUSER_SNAME() -- 'TempUser' PRINT original_login() -- 'MyDomain\Bob.Smith' REVERT; /* REVERT did not work */ print SUSER_SNAME() -- Still `TempUser' print original_login() END; GO
解答
是的,REVERT的生效范围确实和身份切换的上下文绑定,默认情况下,EXECUTE AS 发起的身份切换上下文限定在当前存储过程的执行范围内,跨存储过程调用时,子存储过程没法直接通过REVERT回退到发起切换之前的身份。
具体原因如下:
- 当你在Sales.spExec1中执行
EXECUTE AS USER = 'TempUser'时,SQL Server会创建一个执行上下文栈,这个栈的作用域仅限于当前存储过程的执行上下文。 - 调用dbo.spExec2时,子存储过程会继承当前的执行身份(TempUser),但它无权操作父存储过程创建的上下文栈。
- REVERT语句的作用是弹出当前上下文栈的顶部元素,而子存储过程的上下文栈里并没有父存储过程中EXECUTE AS创建的条目,所以执行REVERT不会产生任何效果,身份依然保持为TempUser。
如果需要在子存储过程中也能回退身份,可以参考两种处理方式:
- 在子存储过程中显式使用
EXECUTE AS CALLER(或其他合适的身份切换语句),不过这需要提前规划好权限配置。 - 把身份切换的逻辑统一放在父存储过程中管理,子存储过程只负责业务逻辑,由父存储过程完成REVERT操作。
内容的提问来源于stack exchange,提问作者fdkgfosfskjdlsjdlkfsf
相关产品推荐
相关产品推荐

