SqlContext 对象

适用范围:SQL Server

调用过程或函数时、在公共语言运行时(CLR)用户定义类型上调用方法或操作触发任何 .NET Framework 语言中定义的触发器时,会在服务器中调用托管代码。 由于在用户连接过程中需要执行此代码,因此需要从服务器上运行的代码访问调用方的上下文。 此外,某些数据访问操作仅在调用方上下文下运行时才有效。 例如,访问触发器操作中使用的插入和删除的伪表只在调用方的上下文中有效。

调用方上下文在 SqlContext 对象中抽象化。 有关详细信息,请参阅 Microsoft.SqlServer.Server.SqlContext

SqlContext 提供对以下组件的访问。

元件 描述
SqlPipe 此对象表示 管道 结果流向客户端。 有关详细信息,请参阅 SqlPipe 对象
SqlTriggerContext 只能在 CLR 触发器中检索此对象。 它提供有关导致触发器被激发的操作的信息,以及所更新的列的映射。 有关详细信息,请参阅 SqlTriggerContext 对象
IsAvailable 此属性用于确定上下文可用性。
WindowsIdentity 此属性用于检索调用者的 Windows 标识。

确定上下文可用性

通过检查 SqlContext 对象的 IsAvailable 属性,查询 SqlContext 类以查看当前正在执行的代码是否正在进程内运行。 IsAvailable 属性是只读的,如果调用代码在 SQL Server 中运行,并且可以访问其他 SqlContext 成员,则返回 True。 如果 IsAvailable 属性返回 False,则所有其他 SqlContext 成员将引发 InvalidOperationException(如果使用)。 如果 IsAvailable 返回 False,则尝试打开连接字符串中具有“context connection=true”的连接对象将失败。

检索 Windows 标识

在 SQL Server 内执行的 CLR 代码始终在进程帐户的上下文中调用。 如果代码应使用调用用户的标识执行某些操作,而不是 SQL Server 进程标识,则应通过 SqlContext 对象的 WindowsIdentity 属性获取模拟令牌。 WindowsIdentity 属性返回表示调用方 Windows 标识的 WindowsIdentity 实例;如果使用 SQL Server 身份验证对客户端进行身份验证,则返回 null。 只有标记为 EXTERNAL_ACCESSUNSAFE 权限的程序集才能访问此属性。

获取 WindowsIdentity 对象后,调用方可以模拟客户端帐户并代表他们执行操作。

仅当启动执行存储过程或函数的客户端使用 Windows 身份验证连接到服务器的存储过程或函数时,才能通过 SqlContext.WindowsIdentity 调用方的身份。 如果改用了 SQL Server 身份验证,则此属性为 null,并且代码无法模拟调用方。

示例

下面的示例说明如何获取调用客户端的 Windows 标识并模拟该客户端。

[Microsoft.SqlServer.Server.SqlProcedure]
public static void WindowsIDTestProc()
{
    WindowsIdentity clientId = null;
    WindowsImpersonationContext impersonatedUser = null;

    // Get the client ID.
    clientId = SqlContext.WindowsIdentity;

    // This outer try block is used to thwart exception filter
    // attacks which would prevent the inner finally
    // block from executing and resetting the impersonation.
    try
    {
        try
        {
            impersonatedUser = clientId.Impersonate();
            if (impersonatedUser != null)
            {
                // Perform some action using impersonation.
            }
        }
        finally
        {
            // Undo impersonation.
            if (impersonatedUser != null)
                impersonatedUser.Undo();
        }
    }
    catch
    {
        throw;
    }
}