sql-server – SQL Server模拟和连接池

前端之家收集整理的这篇文章主要介绍了sql-server – SQL Server模拟和连接池前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我已经被赋予了为一个遗留数据库编写一个Web界面的任务,所有这些数据库都是用户所拥有的数据库帐户,并且相应地分配了角色(当用户执行某些操作时,我们有触发器,全部基于user_name() ).

为了使用远程现代的东西,并且避免将用户密码存储在纯文本中,我正在连接一个具有每个用户的模拟权限的App级别的帐户,我正在尝试运行Execute As User = @ username恢复在运行任何sql之前和之后设置和重置执行上下文.

不幸的是,连接池的reset_connection调用正在与我的Connection连接,并且它卷起了一些关于物理连接无效的令人讨厌的错误

我可以通过不使用连接池来解决这个错误.但是,我的应用程序用户需要一个疯狂的权限来实际执行模拟.此外,杀死连接池是一个很大的…

如何在不牺牲安全性或性能的情况下执行此操作?记住,我不能改变我的用户数据库登录的事实,我真的不兴趣以可检索的方式存储用户密码.我唯一的选择是绕过连接池,所以我可以模仿(并使用sa用户,所以我有足够的权限来实际模拟某人)?

解决方法

为了实现一种“假”代理,在应用程序/数据库代码中没有很大的变化,我建议使用 context_info()将当前用户传输到数据库,并通过调用dbo.fn_user_name()替换对user_name()的调用.

关于如何建立此解决方案的示例

创建fn_user_name()函数

我将创建一个函数fn_user_name,它将从连接上的context_info()中提取用户名,或者在没有上下文信息可用的情况下返回user_name().请注意,连接上下文是一个128字节的二进制文件.你放在那里的任何东西都会用零字符填充,为了解决这个问题,我用空格填充值.

create function dbo.fn_user_name()
returns sysname
as
begin
    declare @user sysname = rtrim(convert(nvarchar(64),context_info()))
    if @user is null 
        return user_name()
    return @user
end
go

现在,您可以在代码中找到替换为user_name()的所有调用,并将其替换为此函数.

将上下文嵌入到.net中的数据库调用

这里有2个选项.或者您创建自己的sqlConnection类,或者创建一个工厂方法,它将返回一个打开的sqlconnection,如下所示.工厂方法的问题是,您运行的每个查询都将是2个db调用.这是写最少的代码.

public sqlConnection CreateConnection(string connectionString,string user)
    {
        var conn = new sqlConnection(connectionString);
        using (var cmd = new sqlCommand(
            @"declare @a varbinary(128) = convert(varbinary(128),@user + replicate(N' ',64 - len(@user)))
              set context_info @a",conn))
        {
            cmd.Parameters.Add("@user",sqlDbType.NVarChar,64).Value = user;
            conn.Open();
            cmd.ExecuteNonQuery();
        }
        return conn;
    }

你会用这个:

using(var conn = CreateConnection(connectionString,user))
{
   var cmd = new sqlCommand("select 1",conn);
   return conn.ExecuteScalar()
}

对于sqlConnection的替代版本,您将需要重载DbConnection并实现sqlConnection的所有方法.执行方法将在下面添加查询,并将用户名作为附加参数传入.

declare @a varbinary(128) = convert(varbinary(128),64 - len(@user)))
set context_info @a

那个类将被用作:

using(var conn = new sqlContextInfoConnection(connectionString,conn);
   conn.open;
   return conn.ExecuteScalar()
}

我会亲自实现选项2,因为它将更接近正常的sqlConnection的工作方式.

猜你在找的MsSQL相关文章