关于c#:如何使用SQL参数从SQL Server获取数据集

How to use SQL parameters to get dataset from SQL Server

我在做C项目,我对这项技术很陌生。

我想从SQL Server 2008中读取一些数据,并编写以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public User select(string username, string password)
{
    string connection = ConfigurationManager.ConnectionStrings["lawyersDBConnectionString"].ConnectionString.ToString();
    string sql = string.Format("select * from users where userName = '{0}' and password = '{1}'", username, password);

    SqlConnection con = new SqlConnection();            
    con.ConnectionString = connection;

    DataSet ds = new DataSet();
    SqlDataAdapter da = new SqlDataAdapter(sql, con);            

    User user = new User();
    DataRow dr;

    try
    {
            da.Fill(ds);
            dr = ds.Tables[0].Rows[0];

            user.Id = Convert.ToInt16(dr["userID"]);                
            user.FirstName = (string)dr["firstName"];
            user.LastName = (string)dr["lastName"];
            user.Email = (string)dr["email"];
            user.Username = (string)dr["userName"];
            user.Password = (string)dr["password"];
            user.type = (string)dr["type"];

            return user;
    }
    catch (Exception ex)
    {                
            return null;
    }
}//end of select method

但我读过一篇关于SQL注入的文章,我想使用SQL参数来避免这种情况,但我不知道如何避免。


这是对代码的简单重做。未测试,但本质上它包括在可释放对象周围添加using语句,以及在参数集合中使用sqlcommand

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
string connection = ConfigurationManager.ConnectionStrings ["lawyersDBConnectionString"].ConnectionString.ToString();
string sql ="select * from users where userName = @uname and password = @pwd";

 DataSet ds = new DataSet();
 using(SqlConnection con = new SqlConnection(connection))
 using(SqlCommand cmd = new SqlCommand(sql, con))
 {
    con.Open();
    cmd.Parameters.AddWithValue("@uname", username);
    cmd.Parameters.AddWithValue("@pwd", password);

    using(SqlDataAdapter da = new SqlDataAdapter(cmd))
    {
         User user = new User();
         DataRow dr;
         da.Fill(ds);
         dr = ds.Tables[0].Rows[0];

         user.Id = Convert.ToInt16(dr["userID"]);                
         user.FirstName = (string)dr["firstName"];
         user.LastName = (string)dr["lastName"];
         user.Email = (string)dr["email"];
         user.Username = (string)dr["userName"];
         user.Password = (string)dr["password"];
         user.type = (string)dr["type"];
         return user;
    }
}

注意,命令文本不直接包含用户和密码的字符串,而是包含一个简单的参数占位符(@uname and @pwd)。将参数添加到sqlcommand集合时,这些占位符被称为参数名称。

查看检索到的数据的用法,我强烈建议您查看简单的ORM工具,如dapper,它可以直接在用户对象中转换所有这些代码。


有趣的是,string.format的工作方式与SQL参数没有太大的不同。唯一的区别是,您指定每个参数的数据类型,它允许sqlcommand正确地清理(read:prevent sql injection)您用户的输入。

下面是一个示例,说明如何更改代码以使用SQL参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (SqlCommand command = new SqlCommand("select * from users where userName = @pUsername and password = @pPassword", connection))
    {
        command.Parameters.Add(new SqlParameter("pUsername", username));
        command.Parameters.Add(new SqlParameter("pPassword", password));

        DataSet ds = new DataSet();
        SqlDataAdapter da = new SqlDataAdapter(command);  

        // The rest of your code here...
     }
}

不过,我想指出的几点是:

  • 用户名通常不区分大小写,因此查询应该使用like或ucase()比较来查找用户名。
  • 从查询中可以明显看出,您的密码没有散列或加盐。这很糟糕。阅读哈希密码。https://crackstation.net/hashing-security.htm(https://crackstation.net/hashing-security.htm)
  • 基本上,您在这里创建的是一个对象关系管理器。除非你对学习如何开发它特别感兴趣,我强烈建议你使用一个已经过尝试和测试的。我个人用的是氨气。Hibernate被编写为Java的ORM,而.NET非常流行于.NET应用程序。实体框架是微软的ORM。我认为它还不完全符合NHibernate的标准,但它在不断改进。