加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

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

发布时间:2020-12-12 08:44:46 所属栏目:MsSql教程 来源:网络整理
导读:我已经被赋予了为一个遗留数据库编写一个Web界面的任务,所有这些数据库都是用户所拥有的数据库帐户,并且相应地分配了角色(当用户执行某些操作时,我们有触发器,全部基于user_name() ). 为了使用远程现代的东西,并且避免将用户的密码存储在纯文本中,我正在连接
我已经被赋予了为一个遗留数据库编写一个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的工作方式.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读