使 SqlDataAdapter/Datareader “真正只读”

Posted

技术标签:

【中文标题】使 SqlDataAdapter/Datareader “真正只读”【英文标题】:Making SqlDataAdapter/Datareader "Really Read-Only" 【发布时间】:2012-09-21 11:23:36 【问题描述】:

更新的问题:有没有办法强制 dataadapter 只接受不包含任何更新/删除/创建/删除/插入命令的命令,而不是在发送到 dataadapter 之前验证 command.text(否则抛出异常)。 dot net 在 datareader dataadapter 或任何其他中是否提供了任何此类内置功能?

注意:DataReader 返回结果,它也接受更新查询并返回结果。 (我可能会遗漏一些错误,但我在执行阅读器之前显示我的更新命令,然后在成功后显示消息,一切正常

【问题讨论】:

重复 - ***.com/questions/4900630/… 另一种选择可能是使用 DataTable.Load 方法需要一个 SqlDataReader,这样您就不必执行 DataTable.Load(command.ExecuteReader()) 以外的任何操作。 另外请注意,您不应该仅仅依赖这个 - 确保您适当地授予表的 SELECT 权限 (GRANT SELECT ON [Table] TO [User])。有人可能会按照SELECT * FROM User;DROP TABLE User; 的行键入一些内容,这在技术上是一个返回结果集的 sql 语句 :-) SelectCommand 属性只是用于抽象数据加载到适配器中 - 它没有做任何事情来阻止运行错误的 sql。 @John - 请参阅我的第二部分更新。希望对您有所帮助。 【参考方案1】:

你能在字符串中搜索一些关键字吗?像 CREATE、UPDATE、INSERT、DROP 或者查询不以 SELECT 开头?还是太脆弱了?

您可能还想为此创建一个应用程序使用的仅具有读取功能的登录。我不知道对象是否具有该属性,但您可以让服务器拒绝交易。

【讨论】:

是的,这是我在问题中没有提及的选项。但我正在寻找一些技术可靠的。另外在这里我必须使用我想避免的正则表达式 然后我会选择路线 2。设置一个只有 dataReader 的服务器登录。然后使用 Mike 的解决方案让它使用此登录名作为连接字符串。然后,即使他们尝试进行 SELECT 以外的事务,服务器也会拒绝。您可以使用 trycatch 或其他东西相应地处理该异常。 如果用户想使用存储过程怎么办?例如,完全可以传递一个名为 GetAllDataUpdates 的存储过程,它选择数据但包含单词“Update”。解析用户输入很痛苦 :-) 您确实应该在 db 级别应用权限以绝对确定。 更好的。无奈之下,我不得不这样做。【参考方案2】:

您需要做的就是确保没有为DataAdapter 准备任何 INSERT、UPDATE 或 DELETE 语句。您的代码可能如下所示:

var dataAdapter = new SqlDataAdapter("SELECT * FROM table", "connection string");

var dataAdapter = new SqlDataAdapter("SELECT * FROM table", sqlConnectionObject);

然后,你有一个只读数据适配器。

【讨论】:

【参考方案3】:

如果您只想要一个 DataTable,那么下面的方法很短并且降低了复杂性:

public DataTable GetDataForSql(string sql, string connectionString)

    using(SqlConnection connection = new SqlConnection(connectionString))
    
        using(SqlCommand command = new SqlCommand())
        
            command.CommandType = CommandType.Text;
            command.Connection = connection;
            command.CommandText = sql;
            connection.Open();          
            using(SqlDataReader reader = command.ExecuteReader())
            
                DataTable data = new DataTable();
                data.Load(reader);
                return data;
            

        

    


用法:

try
    DataTable results = GetDataForSql("SELECT * FROM Table;", ApplicationSettings["ConnectionString"]);

catch(Exception e)

    //Logging
    //Alert to user that command failed.

这里实际上不需要使用 DataAdapter - 它并不是真正满足您的需求。如果使用了更新、删除或插入命令,为什么还要费心去捕捉异常等?它不适合你想做的事情。

重要注意 SelectCommand 属性没有做任何特殊的事情 - 当 SelectCommand 被执行时,它仍然会运行任何传递给它的命令 - 它只需expects 一个要返回的结果集,如果没有返回结果则返回一个空数据集。

这意味着(并且无论如何您都应该这样做)您应该仅向您希望人们能够查询的表授予 SELECT 权限

编辑

要回答您的其他问题,SqlDataReader 是 ReadOnly,因为它们通过只读的 firehose 样式光标工作。这实际上意味着:

while(reader.Read()) //Reads a row at a time moving forward through the resultset (`cursor`)

   //Allowed
   string name = reader.GetString(reader.GetOrdinal("name"));
   //Not Allowed - the read only bit means you can't update the results as you move through them
   reader.GetString(reader.GetOrdina("name")) = name;

它是只读的,因为它不允许您在浏览记录时更新记录。他们执行的获取结果集的sql没有理由不能更新数据。

【讨论】:

你看到我的更新了吗?我正在使用相同但奇怪的是它正在接受更新查询 @John 这是因为他们都只是执行你传递给它的sql。做你想做的事情的唯一可靠方法是在数据库级别限制权限。 SqlDataReader 和 SelectCommand 是关于从 sql 查询返回结果集 - 它们本身不限制查询 - 你必须这样做:-) 例如:SELECT * FROM Table; UPDATE Table SET Name = 'Stinky'; 是一个完全有效的返回结果的 SQL 语句 - 您可以将其输入数据读取器或 SelectCommand。【参考方案4】:

如果您有只读要求,请让您的 TextBox 使用一个连接字符串,该字符串使用的帐户仅对 SQL 数据库具有 db_datareader 权限。

否则,是什么阻止了正在使用您的控制权的开发人员仅仅连接到数据库并自行使用 SqlCommand 造成严重破坏?

【讨论】:

以上是关于使 SqlDataAdapter/Datareader “真正只读”的主要内容,如果未能解决你的问题,请参考以下文章

使引导容器大小变大会使页面无响应

Css使Div自适应居中

如何用word使图片上下居中

如何使 RelativeLayout 半透明但不使活动

如何使图像自动调整大小,使宽度为 100% 并相应调整高度?

如何才能使图形化管理MySQL更轻松(一)